"""审稿留痕 Repository（四审报告 + 裁决；ARCH §5.4 / §5.5 / §6.1）。

- `record`：T2.2 collect 把并行四审结果 append 一行 `chapter_reviews`（每次审稿一行）。
- `list_for_chapter`：T2.5 审稿历史（新→旧）。
- `set_decisions`：T2.4 验收事务里写本次裁决留痕（`chapter_reviews.decisions`）。

四审只读、不直接写库；本 repo 是「审稿结果落库」与「裁决留痕」的唯一写入点
（不变量 #3：AI 产出经验收 gate）。`record`/`set_decisions` 只 flush 不 commit，
便于在编排/验收事务里组合提交。
"""

from __future__ import annotations

import uuid
from typing import Any, Protocol

from pydantic import BaseModel, Field
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from ww_db.models import ChapterReview


class ReviewView(BaseModel):
    """只读审稿留痕快照（snake_case，frozen）。"""

    model_config = {"frozen": True}

    id: uuid.UUID
    project_id: uuid.UUID
    chapter_no: int
    chapter_version: int | None = None
    conflicts: list[dict[str, Any]] = Field(default_factory=list)
    foreshadow_sug: list[dict[str, Any]] = Field(default_factory=list)
    style: dict[str, Any] | None = None
    pace: dict[str, Any] | None = None
    # 灵感③ advisory 人物塑造审留痕（末位默认 None，优雅降级；不进 conflicts/验收 gate）。
    characterization: dict[str, Any] | None = None
    health_score: int | None = None
    decisions: dict[str, Any] | None = None


class ReviewRepo(Protocol):
    """审稿留痕读写接口（按 project_id 隔离）。"""

    async def record(
        self,
        project_id: uuid.UUID,
        chapter_no: int,
        *,
        chapter_version: int | None = None,
        conflicts: list[dict[str, Any]],
        foreshadow_sug: list[dict[str, Any]] | None = None,
        style: dict[str, Any] | None = None,
        pace: dict[str, Any] | None = None,
        characterization: dict[str, Any] | None = None,
        health_score: int | None = None,
    ) -> ReviewView:
        """append 一行审稿报告（T2.2 collect 写入）。"""
        ...

    async def list_for_chapter(self, project_id: uuid.UUID, chapter_no: int) -> list[ReviewView]:
        """该章审稿历史，新→旧（T2.5）。"""
        ...

    async def set_decisions(self, review_id: uuid.UUID, *, decisions: dict[str, Any]) -> ReviewView:
        """写本次裁决留痕到指定审稿行（T2.4 验收事务）。"""
        ...


def _to_view(row: ChapterReview) -> ReviewView:
    return ReviewView(
        id=row.id,
        project_id=row.project_id,
        chapter_no=row.chapter_no,
        chapter_version=row.chapter_version,
        conflicts=list(row.conflicts or []),
        foreshadow_sug=list(row.foreshadow_sug or []),
        style=row.style,
        pace=row.pace,
        characterization=row.characterization,
        health_score=row.health_score,
        decisions=row.decisions,
    )


class SqlReviewRepo:
    """SQLAlchemy 实现：append 审稿行 + 历史查询 + 裁决留痕（只 flush 不 commit）。"""

    def __init__(self, session: AsyncSession) -> None:
        self._s = session

    async def record(
        self,
        project_id: uuid.UUID,
        chapter_no: int,
        *,
        chapter_version: int | None = None,
        conflicts: list[dict[str, Any]],
        foreshadow_sug: list[dict[str, Any]] | None = None,
        style: dict[str, Any] | None = None,
        pace: dict[str, Any] | None = None,
        characterization: dict[str, Any] | None = None,
        health_score: int | None = None,
    ) -> ReviewView:
        row = ChapterReview(
            project_id=project_id,
            chapter_no=chapter_no,
            chapter_version=chapter_version,
            conflicts=list(conflicts),
            foreshadow_sug=list(foreshadow_sug or []),
            style=style,
            pace=pace,
            characterization=characterization,
            health_score=health_score,
            decisions=None,
        )
        self._s.add(row)
        await self._s.flush()
        await self._s.refresh(row)
        return _to_view(row)

    async def list_for_chapter(self, project_id: uuid.UUID, chapter_no: int) -> list[ReviewView]:
        rows = (
            await self._s.execute(
                select(ChapterReview)
                .where(
                    ChapterReview.project_id == project_id,
                    ChapterReview.chapter_no == chapter_no,
                )
                .order_by(ChapterReview.created_at.desc())
            )
        ).scalars()
        return [_to_view(r) for r in rows]

    async def set_decisions(self, review_id: uuid.UUID, *, decisions: dict[str, Any]) -> ReviewView:
        row = (
            await self._s.execute(select(ChapterReview).where(ChapterReview.id == review_id))
        ).scalar_one_or_none()
        if row is None:
            raise LookupError(f"chapter_review not found: {review_id}")
        row.decisions = dict(decisions)
        await self._s.flush()
        await self._s.refresh(row)
        return _to_view(row)
