"""伏笔登记 / 状态变更端点的请求/响应 schema（C3 扩 / ARCH §6.2, §7.2）。

snake_case；前端经 OpenAPI 生成 TS 类型消费。改字段 → 前端必须 `pnpm gen:api`。
登记是**作者显式动作**（不变量 #3：伏笔入库不经 AI 静默写库），到期扫描是验收后的
确定性纯函数置位（M3-d），二者都不在审稿/写章流水线里。
"""

from __future__ import annotations

from typing import Any

from pydantic import BaseModel, Field


class ForeshadowRegisterRequest(BaseModel):
    """POST /projects/:id/foreshadow：作者显式登记一条伏笔（status 落 OPEN）。"""

    code: str = Field(min_length=1, description="伏笔代号，`(project_id, code)` 唯一")
    title: str = Field(min_length=1, description="伏笔标题/一句话描述")
    planted_at: int | None = Field(default=None, description="埋设章号")
    content: str | None = Field(default=None, description="伏笔正文/线索")
    expected_close_from: int | None = Field(default=None, description="预期回收窗口起始章")
    expected_close_to: int | None = Field(
        default=None, description="预期回收窗口结束章（到期判据用）"
    )
    importance: str | None = Field(default=None, description="重要度（自由文本，看板用）")


class ForeshadowTransitionRequest(BaseModel):
    """PATCH /projects/:id/foreshadow/:code：状态机转移 和/或 追加一条进展。

    两字段皆可选：`to_status` 走状态机（非法 → VALIDATION 信封）；`progress_entry`
    append-only 追加到 progress JSONB。二者可同时给（先转移、后追加进展）。
    """

    to_status: str | None = Field(
        default=None, description="目标状态（OPEN/PARTIAL/CLOSED/OVERDUE）"
    )
    progress_entry: dict[str, Any] | None = Field(
        default=None, description="追加一条进展记录（append-only，不覆盖历史）"
    )


class ForeshadowView(BaseModel):
    """伏笔账本视图（登记/状态变更/看板共用；snake_case）。形对齐 `ForeshadowLedgerView`。"""

    code: str
    title: str
    status: str
    planted_at: int | None = None
    content: str | None = None
    expected_close_from: int | None = None
    expected_close_to: int | None = None
    importance: str | None = None
    links: list[dict[str, Any]] = Field(default_factory=list)
    progress: list[dict[str, Any]] = Field(default_factory=list)


class ForeshadowBoardResponse(BaseModel):
    """GET /projects/:id/foreshadow?status=：伏笔看板（四泳道 + OVERDUE 字段齐）。

    `status` 缺省返回全部；按 `code` 升序（repo `list_by_status` 已排序）。前端按
    `status` 分四泳道（OPEN/PARTIAL/CLOSED/OVERDUE），用 `expected_close_to` 标逾期。
    """

    foreshadow: list[ForeshadowView] = Field(default_factory=list)
