"""AI 对话（聊天记录）端点的请求/响应 schema（AC-2 / ai-chat-history-plan §3.2）。

snake_case；前端经 OpenAPI 生成 TS 类型消费（改字段 → 前端 `pnpm gen:api`）。
`Literal` 是 kind/role 的**枚举权威**（DB 列自由 Text，边界在此收窄）：非法 kind/role → 422。
批级字段（thread_id/chapter_no/kind/tool_key）提到请求顶层，`messages` 是本批各条 bubble。
长文进 `content`（有手稿级上限），`meta` 有序列化上界兜底防绕过 content 上限。
"""

from __future__ import annotations

import json
import uuid
from datetime import datetime
from typing import Annotated, Any, Literal

from pydantic import BaseModel, Field, StringConstraints, field_validator

# kind/role 的枚举权威（DB 列自由 Text；加新 kind 改这里 + 零迁移）。
AiKind = Literal["refine", "rewrite", "clarify", "continue", "generator"]
AiRole = Literal["author", "ai"]

# content 上界 = 手稿上限（rewrite 整章文本级）；命名常量非魔法数（CR-H9）。
AI_MESSAGE_CONTENT_MAX = 200_000
# meta 序列化上界兜底：防长文绕过 content 上限塞进 meta。
_META_MAX_SERIALIZED = 50_000
# 一次 append 的最大条数（一次交换的多轮 bubble）。
_MAX_TURNS_PER_CALL = 50


class AiMessageInput(BaseModel):
    """一条待落库 bubble（角色 + 人读文本 + 结构化 meta）。"""

    role: AiRole
    content: Annotated[str, StringConstraints(min_length=1, max_length=AI_MESSAGE_CONTENT_MAX)]
    meta: dict[str, Any] = Field(default_factory=dict)

    @field_validator("meta")
    @classmethod
    def _bound_meta(cls, v: dict[str, Any]) -> dict[str, Any]:
        if len(json.dumps(v, ensure_ascii=False)) > _META_MAX_SERIALIZED:
            raise ValueError("meta too large; put long text in content")
        return v


class AiMessageAppendRequest(BaseModel):
    """POST /projects/{id}/ai-messages：一次交换的一批 bubble（批级字段提顶层）。"""

    thread_id: uuid.UUID
    chapter_no: Annotated[int, Field(ge=1)] | None = None  # NULL = 项目级(工具箱)
    kind: AiKind
    tool_key: str | None = None
    messages: Annotated[list[AiMessageInput], Field(min_length=1, max_length=_MAX_TURNS_PER_CALL)]


class AiMessageView(BaseModel):
    """聊天留痕视图（append/list 回显；snake_case，镜像 repo view）。"""

    id: uuid.UUID
    project_id: uuid.UUID
    chapter_no: int | None
    thread_id: uuid.UUID
    seq: int
    kind: str
    tool_key: str | None
    role: str
    content: str
    meta: dict[str, Any] = Field(default_factory=dict)
    created_at: datetime


class AiMessageListResponse(BaseModel):
    """append/list 信封：`messages` 复数键（repo 约定，非 `items`）。"""

    messages: list[AiMessageView]
