#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.12"
# dependencies = ["pydantic"]
# ///

# ─── How to run ───
# 1. Install uv: curl -LsSf https://astral.sh/uv/install.sh | sh
# 2. Use through: uv run python scripts/run_nutricoach_v140_golden_path.py --help
# ──────────────────

"""Typed boundaries shared by Todo10 Golden Path processes."""

from __future__ import annotations

from dataclasses import dataclass
from enum import StrEnum
from pathlib import Path
from typing import ClassVar, NewType, override

from pydantic import BaseModel, ConfigDict, Field

ProcessStep = NewType("ProcessStep", str)


class ProviderMode(StrEnum):
    DELIVERED = "delivered"
    KNOWN_FAILURE = "known_failure"
    UNKNOWN = "unknown"
    CRASH = "crash"


class FaultOutcome(StrEnum):
    RECONCILED_SUCCESS = "reconciled_success"
    TERMINAL_UNKNOWN = "terminal_unknown"


class StepKind(StrEnum):
    TICK = "tick"
    SUBMIT = "submit"


class StepRequest(BaseModel):
    model_config: ClassVar[ConfigDict] = ConfigDict(frozen=True, extra="forbid")

    step_id: str
    kind: StepKind
    now: str
    provider_mode: ProviderMode = ProviderMode.DELIVERED
    submission_ordinal: int | None = None
    failpoint: str | None = None


class ProcessEvidence(BaseModel):
    model_config: ClassVar[ConfigDict] = ConfigDict(frozen=True, extra="forbid")

    step_id: str
    pid: int
    start_epoch_ns: int
    reopened_authoritative_stores: bool
    exit_code: int


class ProviderCall(BaseModel):
    model_config: ClassVar[ConfigDict] = ConfigDict(frozen=True, extra="forbid")

    sequence: int
    call_key: str
    kind: str
    kst_day: str
    chat_id: str
    topic_id: str
    message_id: str
    text_sha256: str
    outcome: str
    privacy_schema: str
    privacy_scan_count: int
    privacy_leak_categories: tuple[str, ...]


class FaultEvidence(BaseModel):
    model_config: ClassVar[ConfigDict] = ConfigDict(frozen=True, extra="forbid")

    source: str
    row_id: str
    row_digest: str
    state: str


class FaultResult(BaseModel):
    model_config: ClassVar[ConfigDict] = ConfigDict(frozen=True, extra="forbid")

    boundary: str
    step_id: str
    crash_exit: int
    restart_exit: int
    duplicate_provider_calls: int
    outcome: FaultOutcome
    evidence: tuple[FaultEvidence, ...]


class ManifestMember(BaseModel):
    model_config: ClassVar[ConfigDict] = ConfigDict(frozen=True, extra="forbid")

    path: str
    schema_name: str = Field(alias="schema")
    sha256: str
    size: int


@dataclass(frozen=True, slots=True)
class CliError(Exception):
    reason: str

    @override
    def __str__(self) -> str:
        return self.reason


@dataclass(frozen=True, slots=True)
class GenerateOptions:
    root: Path
    receipt: Path
    manifest: Path


@dataclass(frozen=True, slots=True)
class VerifyOptions:
    root: Path
    receipt: Path
    manifest: Path
