"""Projection schema for the selector-scoped board read model."""

from __future__ import annotations

from pydantic import BaseModel, ConfigDict, Field

from recoil.api.schemas._base import _Versioned


class BeatRefModel(BaseModel):
    """Serializable view of the resolver's BeatRef."""

    model_config = ConfigDict(populate_by_name=True, frozen=True)

    project: str
    episode: int
    strategy: str
    ordinal: int
    scene_id: str
    selector: str

    @classmethod
    def from_ref(cls, ref) -> "BeatRefModel":
        from dataclasses import asdict

        d = asdict(ref)
        d.pop("scene_path", None)
        return cls(**d)


class StoryGateSummary(BaseModel):
    """Typed public projection of beat.board.story_gate."""

    model_config = ConfigDict(populate_by_name=True, frozen=True, extra="ignore")

    mode: str | None = None
    route: str | None = None
    confidence: float | None = None
    verdict_path: str | None = None

    @classmethod
    def from_gate(cls, gate) -> "StoryGateSummary | None":
        if not gate:
            return None
        return cls(
            mode=gate.get("mode"),
            route=gate.get("route"),
            confidence=gate.get("confidence"),
            verdict_path=gate.get("verdict_path"),
        )


class BoardProvenance(BaseModel):
    """Selection provenance projected from beat.board."""

    model_config = ConfigDict(populate_by_name=True, frozen=True)

    status: str | None
    approved_by: str | None
    source_sha256: str | None
    version: int | None
    updated_at: str | None
    gate: StoryGateSummary | None


class BoardDetail(BaseModel):
    """Typed public projection of the pointed board sidecar."""

    model_config = ConfigDict(populate_by_name=True, frozen=True, extra="ignore")

    status: str | None = None
    approved_by: str | None = None

    @classmethod
    def from_sidecar(cls, sidecar) -> "BoardDetail | None":
        if not sidecar:
            return None
        return cls(
            status=sidecar.get("status"),
            approved_by=sidecar.get("approved_by"),
        )


class BoardModel(_Versioned):
    """Top-level HTTP response envelope for the board read model."""

    ref: BeatRefModel
    board_artifact: str | None
    board: BoardDetail | None
    provenance: BoardProvenance | None
    candidates: list[str] = Field(default_factory=list)
    versions: list[int] = Field(default_factory=list)
    newer_unpointed_versions: int = 0
    reason: str | None = None
    detail_status: str | None = None
