"""Disposable host for NutriCoach v1.5 live transaction tests."""

from __future__ import annotations

import json
import shutil
from pathlib import Path
import sys
from typing import TYPE_CHECKING, final

sys.path.insert(0, str(Path(__file__).parents[1] / "dualcoach/profile"))

from checkin_cli.customer_coaching import load_customer_registry
from checkin_cli.customer_schedule import initialize_schedule_delivery_fence
from checkin_cli.store import CanonicalEventTransaction
from scripts.nutricoach_v140_authority_fixture import registry_payload
from scripts.nutricoach_v150_live_transaction import TransactionError

if TYPE_CHECKING:
    from scripts.nutricoach_v150_live_transaction import ExecutionBinding


def prepare_weekly_profile(profile: Path, registry: Path, config: Path) -> None:
    """Create the pre-v1.5 registry and canonical schedule stores."""
    registry.parent.mkdir(parents=True)
    _ = registry.write_text(json.dumps(registry_payload()) + "\n", encoding="utf-8")
    registry.chmod(0o600)
    _ = config.write_text(
        "".join((
            "platforms:\n",
            "  telegram:\n",
            "    extra:\n",
            "      nutrition_coaching:\n",
            "        operator_review:\n",
            "          user_id: '100'\n",
            "          chat_id: '200'\n",
            "          topic_id: 59\n",
        )),
        encoding="utf-8",
    )
    runtime = load_customer_registry(registry, profile).customers[0]
    for directory in (
        runtime.customer_root,
        runtime.wizard_root,
        runtime.nutrition_plans_root,
    ):
        directory.mkdir(parents=True, mode=0o700)
    transaction = CanonicalEventTransaction.for_customer_runtime(runtime)
    for path in (transaction.events_path, transaction.sequence_path):
        path.touch(mode=0o600)
        path.chmod(0o600)
    _ = transaction.read_snapshot()
    data = profile / "data"
    ledger = data / "scheduled-deliveries.jsonl"
    ledger.touch(mode=0o600)
    ledger.chmod(0o600)
    (data / "customer-schedule-claims").mkdir(mode=0o700)
    _ = initialize_schedule_delivery_fence(profile)


@final
class FakeHost:
    """Record the exact stop-through-fence sequence with one fault."""

    def __init__(self, root: Path, fault: str | None = None) -> None:
        self.root = root
        self.fault = fault
        self.running = True
        self.stages: list[str] = []

    def _hit(self, stage: str) -> None:
        self.stages.append(stage)
        if self.fault == stage:
            self.fault = None
            raise TransactionError(stage)
        if self.fault == "base_exception" and stage == "install":
            raise KeyboardInterrupt

    def active(self) -> bool:
        return self.running

    def stop(self) -> None:
        self._hit("stop")
        self.running = False

    def stopped_probe(self, binding: ExecutionBinding) -> None:
        del binding
        self._hit("stopped_probe")

    def install(self, binding: ExecutionBinding) -> None:
        binding.successor_runtime.mkdir(parents=True, exist_ok=True)
        self._hit("install")

    def off_smoke(self, binding: ExecutionBinding) -> None:
        if binding.channel_inbox_authorized:
            raise AssertionError
        self._hit("off_smoke")

    def migration_dry_run(self, binding: ExecutionBinding) -> None:
        if binding.capacity != 5 or not binding.weekly_pilot_authorized:
            raise AssertionError
        self._hit("migration_dry_run")

    def migration_apply(self, binding: ExecutionBinding) -> None:
        del binding
        authority = self.root / "profile/data/weekly-pilot-authority"
        authority.mkdir(parents=True)
        registry = self.root / "profile/customers/registry.json"
        _ = registry.write_bytes(b'{"capacity":5}\n')
        self._hit("migration_apply")

    def switch_systemd(self, binding: ExecutionBinding) -> None:
        del binding
        _ = (self.root / "gateway.service").write_text("successor\n")
        self._hit("switch_systemd")

    def reload(self) -> None:
        self._hit("reload")

    def start(self) -> None:
        self._hit("start")
        self.running = True

    def post_fence(self, binding: ExecutionBinding) -> None:
        del binding
        self._hit("post_fence")

    def remove_created(self, binding: ExecutionBinding) -> None:
        for path in (
            binding.successor_runtime,
            self.root / "profile/data/weekly-pilot-authority",
        ):
            if path.exists():
                shutil.rmtree(path)
        self._hit("remove_created")
