"""文风指纹**写侧** Repository（版本化 append + 最新指纹读取；ARCH §5.4 / §6.9）。

读侧（`latest`，供 assemble 注入 stable_core 文风段）已在
`ww_core.memory.sql_repositories.SqlStyleRepo` / `domain.repositories.StyleRepo` 提供，
但其 `StyleView` **只含 `dimensions`**（C5 assemble 只需维度文本，不需证据/版本）。
本模块加**写**能力 + 一个含证据/版本的完整读视图（供 T4.3 `GET /projects/:id/style`
展示完整指纹，对齐 UX §6.9），命名加 `Write` 前缀避免与 C5 读侧 `SqlStyleRepo` 同名歧义
（同 `DigestAppendRepo`/`SqlOutlineWriteRepo` 先例，见 memory/decisions），且**不动 C5 读侧**。

**提交边界**（同 M2/M3 写侧 repo 与 memory/gotchas「写库副作用归调用方」纪律）：
`append` **只 `flush()`（+`refresh`）不 `commit()`**——提交交 `run_job`（学文风后台任务）/端点。

版本化：`style_fingerprint` 每次提取 INSERT 新行（不覆盖历史），`version` = 当前
project 的 `max(version) + 1`（首次 = 1）。提取产 `StyleFingerprintResult` 由调用方拆成
`dimensions_json = {dim.name: dim.value}` + `evidence_json = {dim.name: dim.evidence}`。
"""

from __future__ import annotations

import uuid
from typing import Any, Protocol

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


class StyleFingerprintView(BaseModel):
    """文风指纹完整只读快照（snake_case，frozen）——含维度 + 证据 + 版本。

    区别于 C5 读侧最小 `StyleView`（只 `dimensions`）：本视图供 `GET /style`
    展示完整指纹（每维度名 → 值 + 原文证据列表）。
    """

    model_config = {"frozen": True}

    dimensions: dict[str, Any] = Field(default_factory=dict)
    evidence: dict[str, Any] = Field(default_factory=dict)
    version: int


class StyleFingerprintWriteRepo(Protocol):
    """文风指纹写侧接口（按 project_id 隔离；`append` 只 flush 不 commit）。"""

    async def append(
        self,
        project_id: uuid.UUID,
        *,
        dimensions_json: dict[str, Any],
        evidence_json: dict[str, Any],
    ) -> int:
        """追加一行文风指纹（不覆盖历史），返回新行 `version`（= 当前 max + 1，首次 = 1）。"""
        ...

    async def latest(self, project_id: uuid.UUID) -> StyleFingerprintView | None:
        """取最新版本指纹（version 最大）的完整视图（含证据），无则 None。"""
        ...


class SqlStyleFingerprintWriteRepo:
    """SQLAlchemy 实现：版本化 INSERT（append-only）+ 最新指纹读取（只 flush 不 commit）。"""

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

    async def append(
        self,
        project_id: uuid.UUID,
        *,
        dimensions_json: dict[str, Any],
        evidence_json: dict[str, Any],
    ) -> int:
        current_max = (
            await self._s.execute(
                select(func.max(StyleFingerprint.version)).where(
                    StyleFingerprint.project_id == project_id
                )
            )
        ).scalar_one_or_none()
        next_version = (current_max or 0) + 1
        row = StyleFingerprint(
            project_id=project_id,
            dimensions_json=dict(dimensions_json),
            evidence_json=dict(evidence_json),
            version=next_version,
        )
        self._s.add(row)
        await self._s.flush()
        await self._s.refresh(row)
        return row.version

    async def latest(self, project_id: uuid.UUID) -> StyleFingerprintView | None:
        row = (
            await self._s.execute(
                select(StyleFingerprint)
                .where(StyleFingerprint.project_id == project_id)
                .order_by(StyleFingerprint.version.desc())
                .limit(1)
            )
        ).scalar_one_or_none()
        if row is None:
            return None
        return StyleFingerprintView(
            dimensions=dict(row.dimensions_json),
            evidence=dict(row.evidence_json),
            version=row.version,
        )
