"""Typed store seam for installed WeeklyOperationsStore read/append."""

from __future__ import annotations

import json
from dataclasses import dataclass
from datetime import date, datetime
from typing import ClassVar, Protocol

from pydantic import BaseModel, ConfigDict

from .contract import SOURCE_ROW_DIGEST, canonical_source_frame


class StoreError(RuntimeError):
    """Installed store behavior violates the sealed continuity contract."""


class ContinuityRow(BaseModel):
    """Minimal strict view of the installed durable row."""

    model_config: ClassVar[ConfigDict] = ConfigDict(frozen=True, extra="forbid")
    canonical_digest: str
    canonical_sequence: int
    customer_identity_digest: str
    kst_day: date
    logical_key: str
    occurred_at_kst: datetime
    predecessor_row_digest: str
    reminder_audit_id: str | None
    reminder_reservation_id: str | None
    row_digest: str
    schema_version: str
    source_event_digest: str | None
    source_event_id: str | None
    state: str

    def canonical_frame(self) -> bytes:
        """Encode this row in the installed canonical shape."""
        return (
            json.dumps(self.model_dump(mode="json"), sort_keys=True, separators=(",", ":")).encode()
            + b"\n"
        )


@dataclass(frozen=True, slots=True)
class ReissueOperation:
    """All semantic fields passed to the installed append operation."""

    row: ContinuityRow


@dataclass(frozen=True, slots=True)
class AppendOutcome:
    """Installed append result projected into package types."""

    row: ContinuityRow
    appended: bool


class OperationsStore(Protocol):
    """Narrow installed WeeklyOperationsStore contract."""

    def read(self) -> tuple[ContinuityRow, ...]: ...

    def append(self, operation: ReissueOperation) -> AppendOutcome: ...


def source_row() -> ContinuityRow:
    """Parse the authenticated source frame once at the package boundary."""
    row = ContinuityRow.model_validate_json(canonical_source_frame())
    if row.row_digest != SOURCE_ROW_DIGEST:
        raise StoreError("source row digest")
    return row
