"""本章注入透明（B0）的请求/响应 schema（C 扩 / ARCH §3.4、§5.3）。

snake_case；前端经 OpenAPI 生成 TS 类型消费。改字段 → 前端必须 `pnpm gen:api`。
读取无 LLM、无 commit——回放 assemble() 的确定性 SelectionTrace（不变量 #6）。
可控版（PUT）存作者覆盖：pin 强制纳入 / excluded 强制剔除 / recent_n 覆盖回看章数，
本身仍是确定性输入，故「看到的=写章用的」成立。
"""

from __future__ import annotations

import uuid

from pydantic import BaseModel, Field

# recent_n 合法区间（回看近况摘要章数）——下限 1，上限防作者误填爆 token。
RECENT_N_MIN = 1
RECENT_N_MAX = 20


class InjectionEntity(BaseModel):
    """一个被注入本章上下文的实体 + 入选理由（喂给透明面板的徽标）。"""

    kind: str = Field(description="character / world_entity")
    name: str
    reasons: list[str] = Field(
        default_factory=list,
        description="explicit_beat/main_character/recent_digest/foreshadow_window/author_pin",
    )


class InjectionEntityRef(BaseModel):
    """作者 pin/排除点名的实体引用（kind + name）。"""

    kind: str = Field(description="character / world_entity")
    name: str


class InjectionOverrideRequest(BaseModel):
    """PUT /projects/:id/chapters/:no/injection：作者对本章注入的覆盖。

    pinned 强制纳入（加 author_pin 理由）；excluded 强制剔除；recent_n 覆盖近况回看章数
    （None=用默认）。空覆盖 = 纯自动选择。
    """

    pinned: list[InjectionEntityRef] = Field(default_factory=list)
    excluded: list[InjectionEntityRef] = Field(default_factory=list)
    recent_n: int | None = Field(default=None, ge=RECENT_N_MIN, le=RECENT_N_MAX)


class InjectionResponse(BaseModel):
    """GET/PUT /projects/:id/chapters/:no/injection：本章注入留痕 + 作者覆盖回显。"""

    project_id: uuid.UUID
    chapter_no: int
    selected: list[InjectionEntity] = Field(default_factory=list)
    recent_n: int = Field(description="生效的近况回看章数（默认或被 override 覆盖后的值）")
    pinned: list[InjectionEntityRef] = Field(
        default_factory=list, description="作者强制纳入的实体（回显）"
    )
    excluded: list[InjectionEntityRef] = Field(
        default_factory=list, description="作者强制剔除的实体（回显，供面板恢复）"
    )
