"""Immutable closure regressions for the V15 live launcher."""

from __future__ import annotations

import hashlib
import json
import os
import shutil
import subprocess
import sys
from pathlib import Path

import pytest

from scripts.execute_nutricoach_v150_sealed_live import sandbox_command
from scripts.nutricoach_v150_detached_bootstrap import (
    PRESEAL,
    BootstrapDenied,
    verify_package_inventory,
)
from scripts.seal_nutricoach_v150_candidate import candidate_source_paths
from scripts.verify_nutricoach_v140_candidate_core import (
    CandidateContractError,
    load_json,
    require_object,
)
from scripts.verify_nutricoach_v150_candidate_inputs import (
    _SUCCESSOR_OVERLAY_PATHS,
    verify_v17_overlay,
)

EVIDENCE = (
    Path("/home/cube/projects/richard/traning coach")
    / ".omo/evidence/nutricoach-v150-combined/task-v15r71-candidate"
)
HERMES_WHEEL = EVIDENCE / "artifacts/build-1/hermes_agent-0.17.0-py3-none-any.whl"
PROFILE_WHEEL = (
    EVIDENCE / "artifacts/build-1/physique_checkin_cli-0.1.0-py3-none-any.whl"
)


def _detached_pythonpath(source: Path) -> str:
    return os.pathsep.join((str(HERMES_WHEEL), str(PROFILE_WHEEL), str(source)))


_STEPPER_OVERLAY_PATHS = {
    "dualcoach/profile/checkin_cli/wizard.py",
    "dualcoach/profile/checkin_cli/wizard_models.py",
    "gateway/platforms/physique_checkin.py",
    "gateway/platforms/physique_checkin_bindings.py",
    "gateway/platforms/telegram.py",
    "gateway/platforms/telegram_checkin_stepper_transport.py",
    "gateway/platforms/telegram_physique_checkin_stepper.py",
}


def test_fresh_launcher_targets_r71_closure() -> None:
    assert PRESEAL.name == "live-transaction-preseal-v15-runtime-authority-r71"
    assert any(
        "live-transaction-preseal-v15-runtime-authority-r71" in argument
        and argument.endswith("nutricoach_v150_detached_bootstrap.py")
        for argument in sandbox_command("approval")
    )


def test_successor_overlay_contains_every_stepper_wheel_source() -> None:
    assert _STEPPER_OVERLAY_PATHS <= _SUCCESSOR_OVERLAY_PATHS


@pytest.mark.parametrize("omitted", sorted(_STEPPER_OVERLAY_PATHS))
def test_successor_overlay_rejects_each_omitted_stepper_source(
    tmp_path: Path,
    omitted: str,
) -> None:
    inputs = tmp_path / "inputs"
    inputs.mkdir()
    digest = "0" * 64
    overlay_paths = _SUCCESSOR_OVERLAY_PATHS | _STEPPER_OVERLAY_PATHS
    overlay = overlay_paths - {omitted}
    _ = (inputs / "successor-overlay.sha256").write_text(
        "".join(f"{digest}  {path}\n" for path in sorted(overlay)),
        encoding="utf-8",
    )
    exact = inputs / "v17-exact-source-set.sha256"
    patch = inputs / "v17-patch-tree.sha256"
    sandbox = inputs / "v17-sandbox.diff"
    for path in (exact, patch, sandbox):
        _ = path.write_bytes(b"")
    _ = (inputs / "v17-evidence-files.sha256").write_text(
        "".join(
            f"{hashlib.sha256(path.read_bytes()).hexdigest()}  /sealed/{name}\n"
            for path, name in (
                (exact, "exact-current-source-set.final.sha256"),
                (patch, "patch-tree.sha256"),
                (sandbox, "sandbox.diff"),
            )
        ),
        encoding="utf-8",
    )
    source_entries = [
        {"path": f"snapshot/source/{path}", "sha256": digest}
        for path in sorted(overlay_paths)
    ]

    with pytest.raises(CandidateContractError, match="successor overlay path set"):
        verify_v17_overlay(tmp_path, source_entries)


def test_live_launcher_writable_binds_external_authority_paths() -> None:
    command = sandbox_command("approval")
    roots = (
        "/home/cube/.hermes/runtime-authority/dualcoach-v1.3.0-owner-risk-first-customer",
        "/home/cube/.hermes/runtime-authority/dualcoach-v1.3.2-daily-checkin-rebound-first-customer-credentials",
    )
    for root in roots:
        index = command.index(root)
        assert command[index - 1] == "--bind"
        assert command[index + 1] == root


def test_package_inventory_rejects_unlisted_file(tmp_path: Path) -> None:
    payload = tmp_path / "payload.json"
    _ = payload.write_text("payload\n", encoding="utf-8")
    digest = hashlib.sha256(payload.read_bytes()).hexdigest()
    manifest = tmp_path / "package-manifest.json"
    _ = manifest.write_text(
        json.dumps({"entries": {"payload.json": digest}}),
        encoding="utf-8",
    )
    payload.chmod(0o444)
    verify_package_inventory(manifest, tmp_path)
    _ = (tmp_path / "unlisted.json").write_text("extra\n", encoding="utf-8")

    with pytest.raises(BootstrapDenied, match="package_inventory"):
        verify_package_inventory(manifest, tmp_path)


def test_candidate_closure_includes_verifier_imports() -> None:
    base = require_object(
        load_json(EVIDENCE / "inputs/base-manifest.json"),
        "base manifest",
    )
    sources = candidate_source_paths(base, EVIDENCE)
    assert Path("scripts/nutricoach_v150_live_upgrade_common.py") in sources
    assert Path("scripts/nutricoach_v150_live_authority.py") in sources
    assert Path("scripts/nutricoach_v150_live_transaction.py") in sources
    assert Path("tests/nutricoach_v150_transaction_support.py") in sources


def test_verifier_imports_from_detached_closure(tmp_path: Path) -> None:
    source_root = Path(__file__).resolve().parents[1]
    base = require_object(
        load_json(EVIDENCE / "inputs/base-manifest.json"),
        "base manifest",
    )
    for relative in candidate_source_paths(base, EVIDENCE):
        destination = tmp_path / relative
        destination.parent.mkdir(parents=True, exist_ok=True)
        _ = shutil.copy2(source_root / relative, destination)
    verifier = tmp_path / "scripts/verify_nutricoach_v150_preseal_v15.py"
    environment = dict(os.environ)
    environment["PYTHONDONTWRITEBYTECODE"] = "1"
    environment["PYTHONPATH"] = _detached_pythonpath(tmp_path)
    result = subprocess.run(
        (sys.executable, "-B", str(verifier)),
        check=False,
        capture_output=True,
        text=True,
        env=environment,
        cwd=tmp_path,
    )
    assert result.returncode in {0, 2}
    assert not result.stderr
    assert result.stdout.startswith(("DENIED:", "{"))


def test_worker_imports_from_detached_closure(tmp_path: Path) -> None:
    source_root = Path(__file__).resolve().parents[1]
    base = require_object(
        load_json(EVIDENCE / "inputs/base-manifest.json"),
        "base manifest",
    )
    for relative in candidate_source_paths(base, EVIDENCE):
        destination = tmp_path / relative
        destination.parent.mkdir(parents=True, exist_ok=True)
        _ = shutil.copy2(source_root / relative, destination)
    environment = dict(os.environ)
    environment["PYTHONDONTWRITEBYTECODE"] = "1"
    environment["PYTHONPATH"] = _detached_pythonpath(tmp_path)
    result = subprocess.run(
        (
            sys.executable,
            "-B",
            "-c",
            "import scripts.nutricoach_v150_controller_worker",
        ),
        check=False,
        capture_output=True,
        text=True,
        env=environment,
        cwd=tmp_path,
    )
    assert result.returncode == 0, result.stderr
