from __future__ import annotations

from typing import List, Optional

from pydantic import BaseModel, Field


class NodeDto(BaseModel):
    """客户端无障碍序列化的节点。占坑期后端不解析,字段保留为兼容未来真实解析。"""

    view_id: Optional[str] = None
    text: Optional[str] = None
    desc: Optional[str] = None
    children: List["NodeDto"] = Field(default_factory=list)


class ClusterDto(BaseModel):
    """Android `/parse` 接口用,id 是 Room 自增整数。"""

    id: int
    title: str


class ParseRequest(BaseModel):
    package_name: str
    tree: Optional[NodeDto] = None
    clusters: List[ClusterDto] = Field(default_factory=list)


class ParseResponse(BaseModel):
    title: str
    price: float
    source_app: str
    cluster_id: Optional[int] = None
    typical_price: float


NodeDto.model_rebuild()


class QuickQuoteRequest(BaseModel):
    """Android `/api/v1/quick-quote` 接口用:用户主动输入商品名查询比价。
    无需 price(用户来查的就是不知道价),只需 title + 已有簇用于归簇判断。
    """

    title: str
    clusters: List[ClusterDto] = Field(default_factory=list)


class QuickQuoteResponse(BaseModel):
    """quick-quote 响应:LLM 估的市场常见价 + 是否命中已有簇。"""

    title: str  # 规范化后的标题(LLM 可能整理一下用户输入)
    typical_price: float  # 市场常见价,LLM 必须给数字
    cluster_id: Optional[int] = None  # 命中已有簇的 id;null 表示用户没记过同款


# ---------- iOS 新接口用的 DTO (cluster id 用字符串以兼容 UUID) ---------- #


class ClusterDtoStr(BaseModel):
    """iOS `/parse-image` / `/parse-text` 接口用,id 是 SwiftData 的 UUID 字符串。"""

    id: str
    title: str


class ParseTextRequest(BaseModel):
    """iOS 手动新建记录时调用:客户端已知 title/price/source_app,
    后端只做归簇 + 估市场常见价。"""

    title: str
    price: float
    source_app: str
    clusters: List[ClusterDtoStr] = Field(default_factory=list)


class ParseStrResponse(BaseModel):
    """iOS 三个接口的统一响应。结构同 ParseResponse,但 cluster_id 是字符串。"""

    title: str
    price: float
    source_app: str
    cluster_id: Optional[str] = None
    typical_price: float


class ParseOcrRequest(BaseModel):
    """iOS 截图 OCR 后调用:客户端只发 OCR 文本 + 已有簇,
    由后端 LLM 抠出 title/price/source_app/cluster_id/typical_price 全部 5 项。"""

    ocr_text: str
    clusters: List[ClusterDtoStr] = Field(default_factory=list)


# ---------- 价保哨兵 ---------- #


class TrackPriceRequest(BaseModel):
    """Android `/api/v1/track-price`:用户告知"我在 X 平台 ¥XXX 买了 Y" → 服务端
    用 LLM 估当前合理价 + 哈希抖动模拟降价,返给客户端做"该申请价保了"通知判断。

    占坑期实现 LLM mock(无真实平台价 API)。未来接真 API 时客户端 0 改动。
    """

    platform: str  # "京东" / "淘宝" / "拼多多" / "抖音" 等中文平台名
    product_title: str  # 商品完整标题
    purchase_price: float  # 用户购买时支付的价格(参考用,实际抖动以 LLM 给的基础价为锚)
    purchase_at: int  # 购买时间(秒级 epoch),用于"距今 N 天"提示 + 抖动种子


class TrackPriceResponse(BaseModel):
    """track-price 响应:当前价 + 跌涨趋势 + 可省金额。

    客户端按 `savings > 0` 决定是否发"该申请价保了"通知。
    """

    current_price: float  # 当前估算价(抖动后的最终输出)
    base_price: float  # LLM 估的"日常常见价",抖动前的锚
    trend: str  # "down" / "flat" / "up"
    savings: float  # purchase_price - current_price;> 0 = 可申请价保
    checked_at: int  # 服务端响应生成时间(秒级 epoch)


# ---------- 多比比新增:比价擂台 ---------- #


class ArenaQuoteRequest(BaseModel):
    """多比比 `/api/v1/arena-quote`:用户输入商品名,后端 LLM 估各平台到手价 + 市场常见价。"""

    title: str
    platforms: Optional[List[str]] = None  # 不传则用后端默认 4 大电商


class ArenaPlatformQuote(BaseModel):
    platform: str
    price: float
    note: str = ""


class ArenaQuoteResponse(BaseModel):
    title: str  # 归一化后的标题
    typical_price: float  # 市场常见价(各平台中位)
    quotes: List[ArenaPlatformQuote]
    lowest_platform: Optional[str] = None


# ---------- 多比比新增:AI 值不值得买 ---------- #


class WorthBuyRequest(BaseModel):
    """多比比 `/api/v1/worth-buy`:给商品 + 当前到手价,LLM 评估值不值得现在买。"""

    title: str
    price: float
    platform: Optional[str] = None


class WorthBuyResponse(BaseModel):
    score: int  # 0-100,越高越值得现在买
    verdict: str  # "buy" / "wait" / "neutral"
    headline: str  # 一句话结论
    reasons: List[str]
    typical_price: float
    best_time: str
