"""群发消息相关数据模型。"""

from __future__ import annotations

from typing import Optional, Literal

from pydantic import BaseModel, Field


class BatchSendRequest(BaseModel):
    """群发请求。

    三层幂等：
    - 批级：client_request_id（None 时自动生成 batch_id）
    - 单条：内部按 f"{batch_id}:{to_wxid}" 作为 client_request_id 传给 orchestrator
    - orchestrator：复用 IdemCache（TTL=300s）
    """

    targets: list[str] = Field(
        ...,
        min_length=1,
        max_length=200,
        description="目标 wxid 列表（去重后 ≤ 200）",
    )
    content: str = Field(
        ...,
        min_length=1,
        max_length=2000,
        description="消息内容（支持 {nickname} 占位符，发送前按目标联系人替换）",
    )
    client_request_id: Optional[str] = Field(
        None,
        description="可选：批级幂等 ID，None 时自动生成 batch_id",
    )
    abort_on_consecutive_fail: int = Field(
        5,
        ge=1,
        le=20,
        description="连续失败 N 次中止整批（剩余标记 skipped）",
    )


class BatchItemResult(BaseModel):
    """单条群发结果。"""

    to_wxid: str
    # unknown: 发送被 cancel 中断，实际发送状态未知（send_queue worker 可能已发出）
    status: Literal["success", "failed", "skipped", "pending", "unknown"]
    error_code: Optional[str] = None
    error_message: Optional[str] = None
    verified: Optional[bool] = None


class BatchSendStatus(BaseModel):
    """群发任务状态。"""

    batch_id: str
    status: Literal["pending", "running", "completed", "failed", "cancelled"] = "pending"
    total: int = 0
    processed: int = 0
    success: int = 0
    failed: int = 0
    skipped: int = 0
    progress: float = Field(0.0, ge=0.0, le=1.0)
    estimated_remaining_sec: Optional[int] = None
    abort_reason: Optional[str] = None
    items: Optional[list[BatchItemResult]] = None  # 详细结果（可选，列表大时省略）
