"""Sealed NutriCoach v1.5 live transaction models and host contract."""

from __future__ import annotations

from dataclasses import dataclass
from pathlib import Path
from typing import Final, Protocol

CANDIDATE_DIGEST: Final = (
    "066a794d44861d2cd0fe8c1ea14c0050e00219b38a2d2026b389772783056dad"
)
MANIFEST_SHA256: Final = (
    "78b2d1790b67cf0d9730cd9a4b0d2d0d3de5bf5f5836e31a70f5be3a62dd7786"
)
PACKAGE_DIGEST: Final = (
    "a362d994b41a5d05ed2fcdafc76482e72d18ff69334cd8249eec061bff733acb"
)
APPROVAL_PHRASE: Final = f"AUTHORIZE NUTRICOACH V1.5 LIVE UPGRADE {PACKAGE_DIGEST}"
CURRENT_RUNTIME: Final = Path(
    "/home/cube/.hermes/profiles/dualcoachtest/.strict-runtime/6c9c4394-v132/venv"
)
HERMES_WHEEL: Final = Path(
    "/home/cube/projects/richard/.worktrees/nutricoach-v150-combined/.omo/evidence/"
    + "nutricoach-v150-combined/task-1-candidate/artifacts/build-1/"
    + "hermes_agent-0.17.0-py3-none-any.whl"
)
PROFILE_WHEEL: Final = HERMES_WHEEL.with_name(
    "physique_checkin_cli-0.1.0-py3-none-any.whl"
)
HERMES_WHEEL_SHA256: Final = (
    "5829f799160a7341f5509043c17cecbe5d10cfe25c44eb3f8fde44bbf9720d91"
)
PROFILE_WHEEL_SHA256: Final = (
    "bdfe94b31d9c98c233301dc2cc552e5e2d672853901bac2bdf73df7e23c709b6"
)
WEEKLY_AUTHORITY_ISSUED_AT: Final = "2026-08-27T00:00:00+09:00"
WEEKLY_AUTHORITY_EXPIRES_AT: Final = "2026-09-30T23:59:59+09:00"


class TransactionError(RuntimeError):
    """Fail-closed live transaction error."""


class ApprovalAlreadyUsed(TransactionError):
    """The sealed one-use authority was already reserved or consumed."""


@dataclass(frozen=True, slots=True)
class ExecutionBinding:
    """Immutable inputs sealed into the live controller."""

    candidate_digest: str
    manifest_sha256: str
    package_digest: str
    current_runtime: Path
    successor_runtime: Path
    hermes_wheel: Path
    hermes_wheel_sha256: str
    profile_wheel: Path
    profile_wheel_sha256: str
    capacity: int
    weekly_pilot_authorized: bool
    channel_inbox_authorized: bool


@dataclass(frozen=True, slots=True)
class LiveOperation:
    """One authorized invocation and its rollback authority paths."""

    binding: ExecutionBinding
    approval: str
    execution_root: Path
    mutable_paths: tuple[Path, ...]


class LiveHost(Protocol):
    """Typed side-effect seam inherited from the v1.4 v7 controller."""

    def active(self) -> bool:
        """Return whether the target service is active."""
        ...

    def stop(self) -> None:
        """Stop the target service synchronously."""
        ...

    def stopped_probe(self, binding: ExecutionBinding) -> None:
        """Fence stopped current bytes and runtime identity."""
        ...

    def install(self, binding: ExecutionBinding) -> None:
        """Install the two exact wheels into a fresh runtime."""
        ...

    def off_smoke(self, binding: ExecutionBinding) -> None:
        """Run installed code while Channel Inbox remains OFF."""
        ...

    def migration_dry_run(self, binding: ExecutionBinding) -> None:
        """Prove weekly pilot and capacity-five migration eligibility."""
        ...

    def migration_apply(self, binding: ExecutionBinding) -> None:
        """Apply the sealed weekly authority and capacity migration."""
        ...

    def switch_systemd(self, binding: ExecutionBinding) -> None:
        """Switch the exact unit contract to the successor runtime."""
        ...

    def reload(self) -> None:
        """Reload the service manager."""
        ...

    def start(self) -> None:
        """Start the target service synchronously."""
        ...

    def post_fence(self, binding: ExecutionBinding) -> None:
        """Fence installed, loaded, capability, and runtime identities."""
        ...

    def remove_created(self, binding: ExecutionBinding) -> None:
        """Remove only successor-owned paths during rollback."""
        ...
