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

# ─── 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
# ──────────────────

"""Fresh-child orchestration for the exact seven-day production scenario."""

from __future__ import annotations

import subprocess
import sys
from datetime import date, datetime
from multiprocessing import get_context
from pathlib import Path
from zoneinfo import ZoneInfo

from scripts.nutricoach_v140_golden_path_models import (
    CliError, ProcessEvidence, ProviderMode, StepKind, StepRequest,
)
from scripts.nutricoach_v140_golden_path_steps import RaceBarrier, RaceLock
from scripts.nutricoach_v140_golden_path_profile import create_profile

KST = ZoneInfo("Asia/Seoul")
ENTRYPOINT = Path(__file__).with_name("run_nutricoach_v140_golden_path.py")


def _at(day: date, hour: int, minute: int = 0) -> str:
    return datetime(day.year, day.month, day.day, hour, minute, tzinfo=KST).isoformat()


def scenario_steps() -> tuple[StepRequest, ...]:
    """Return events only; production scheduling derives all due task variants."""
    mon, tue, wed = date(2026, 8, 17), date(2026, 8, 18), date(2026, 8, 19)
    thu, fri, sat = date(2026, 8, 20), date(2026, 8, 21), date(2026, 8, 22)
    sun = date(2026, 8, 23)
    return (
        StepRequest(step_id="mon-submit", kind=StepKind.SUBMIT, now=_at(mon, 19), submission_ordinal=1),
        StepRequest(step_id="mon-tick", kind=StepKind.TICK, now=_at(mon, 20)),
        StepRequest(step_id="tue-reminder", kind=StepKind.TICK, now=_at(tue, 20)),
        StepRequest(step_id="tue-duplicate", kind=StepKind.TICK, now=_at(tue, 20)),
        StepRequest(step_id="tue-submit", kind=StepKind.SUBMIT, now=_at(tue, 21), submission_ordinal=2),
        StepRequest(step_id="tue-card", kind=StepKind.TICK, now=_at(tue, 21)),
        StepRequest(step_id="wed-known", kind=StepKind.TICK, now=_at(wed, 20), provider_mode=ProviderMode.KNOWN_FAILURE),
        StepRequest(step_id="wed-duplicate", kind=StepKind.TICK, now=_at(wed, 20)),
        StepRequest(step_id="wed-cutoff", kind=StepKind.TICK, now=_at(wed, 23)),
        StepRequest(step_id="thu-submit", kind=StepKind.SUBMIT, now=_at(thu, 19), submission_ordinal=3),
        StepRequest(step_id="thu-tick", kind=StepKind.TICK, now=_at(thu, 20)),
        StepRequest(step_id="fri-reminder", kind=StepKind.TICK, now=_at(fri, 20)),
        StepRequest(step_id="fri-cutoff", kind=StepKind.TICK, now=_at(fri, 23)),
        StepRequest(step_id="fri-submit", kind=StepKind.SUBMIT, now=_at(fri, 23, 1), submission_ordinal=4),
        StepRequest(step_id="fri-edit-unknown", kind=StepKind.TICK, now=_at(fri, 23, 1), provider_mode=ProviderMode.UNKNOWN),
        StepRequest(step_id="fri-edit-replay", kind=StepKind.TICK, now=_at(fri, 23, 1)),
        StepRequest(step_id="sat-reminder", kind=StepKind.TICK, now=_at(sat, 20)),
        StepRequest(step_id="sat-cutoff", kind=StepKind.TICK, now=_at(sat, 23)),
        StepRequest(step_id="sun-submit", kind=StepKind.SUBMIT, now=_at(sun, 19), submission_ordinal=5),
        StepRequest(step_id="sun-tick", kind=StepKind.TICK, now=_at(sun, 20)),
        StepRequest(step_id="following-monday", kind=StepKind.TICK, now="2026-08-24T08:00:00+09:00"),
    )


def _run_child(root: Path, request: StepRequest, ordinal: int) -> ProcessEvidence:
    evidence = root / "processes" / f"{ordinal:03d}-{request.step_id}.json"
    completed = subprocess.run(
        [
            sys.executable, "-B", str(ENTRYPOINT), "--child-step", request.model_dump_json(),
            "--root", str(root), "--process-evidence", str(evidence),
        ],
        check=False, capture_output=True, text=True,
    )
    if completed.returncode != 0:
        raise CliError(
            f"child {request.step_id} failed ({completed.returncode}): {completed.stderr}"
        )
    return ProcessEvidence.model_validate_json(evidence.read_text(encoding="utf-8"))


def _race_worker(
    barrier: RaceBarrier, lock: RaceLock, root: Path, request: StepRequest, evidence: Path,
) -> None:
    from scripts.nutricoach_v140_golden_path_steps import execute_race_tick

    _ = execute_race_tick(root, request, evidence, barrier, lock)


def _run_cutoff_race(
    root: Path, request: StepRequest, ordinal: int,
) -> tuple[ProcessEvidence, ProcessEvidence]:
    context = get_context("spawn")
    barrier = context.Barrier(3)
    lock = context.Lock()
    paths = tuple(
        root / "processes" / f"{ordinal:03d}-{request.step_id}-race-{index}.json"
        for index in (1, 2)
    )
    processes = tuple(
        context.Process(target=_race_worker, args=(barrier, lock, root, request, path))
        for path in paths
    )
    for process in processes:
        process.start()
    _ = barrier.wait(timeout=30)
    for process in processes:
        _ = process.join(timeout=60)
        if process.exitcode != 0:
            raise CliError(f"cutoff race child failed: {process.exitcode}")
    return (
        ProcessEvidence.model_validate_json(paths[0].read_text(encoding="utf-8")),
        ProcessEvidence.model_validate_json(paths[1].read_text(encoding="utf-8")),
    )


def run_scenario(root: Path) -> tuple[ProcessEvidence, ...]:
    """Create once, then reopen production authority in every fresh child."""
    create_profile(root)
    evidence: list[ProcessEvidence] = []
    for ordinal, request in enumerate(scenario_steps(), start=1):
        if request.step_id == "wed-cutoff":
            evidence.extend(_run_cutoff_race(root, request, ordinal))
        else:
            evidence.append(_run_child(root, request, ordinal))
    return tuple(evidence)
