from __future__ import annotations

import hashlib
import importlib.util
import json
import os
from pathlib import Path

HERE = Path(__file__).parent
SPEC = importlib.util.spec_from_file_location("cleanup_v3", HERE / "cleanup_controller.py")
assert SPEC and SPEC.loader
MODULE = importlib.util.module_from_spec(SPEC)
SPEC.loader.exec_module(MODULE)


def test_canonical_json_is_deterministic() -> None:
    assert MODULE.canon({"b": 1, "a": 2}) == b'{"a":2,"b":1}\n'


def test_contract_is_current_candidate_bound() -> None:
    contract = json.loads((HERE / "schema-contract-v3.json").read_text())
    assert contract["bindings"]["candidate_digest"] == "4a6c7ee54cf9526a30de8bb576c1d71b411938beba33a04914738f6e1b6ed1cb"
    assert contract["bindings"]["lifecycle_root_sha256"] == "fdcfb1efd1f2d4a2b95f22f7311827d197898a6d480cb572956e87bd66d20361"
    assert contract["bindings"]["config_sha256"] == "a95a89e838793d246bbbbba0d93da9ab0f2f2726f4fd27864648c4111563f509"


def test_archive_scope_protects_prior_archives() -> None:
    contract = json.loads((HERE / "schema-contract-v3.json").read_text())
    assert {"rehearsal-reset-archives", "profile-reset-archives", "post-lifecycle-cleanup-archives"} <= set(contract["protected_data_roots"])


def test_source_has_archive_before_mutation_and_rollback() -> None:
    source = (HERE / "cleanup_controller.py").read_text()
    execute = source[source.index("def execute("):source.index("def verify_archive(")]
    assert execute.index("archive_prestate(") < execute.index("disable_customer(") < execute.index("patch_delivery_gate(")
    assert "restore_prestate(" in execute
    assert "shutil.rmtree(archive)" not in source


def test_config_edit_uses_apply_patch_only() -> None:
    source = (HERE / "cleanup_controller.py").read_text()
    function = source[source.index("def patch_delivery_gate("):source.index("def qa_and_stop(")]
    assert "args.apply_patch" in function
    assert "atomic(args.profile / \"config.yaml\"" not in function


def test_stale_controller_unchanged() -> None:
    stale = HERE.parent / "reset-controller-st_01a0054d/post-lifecycle-cleanup-v2/cleanup_controller.py"
    assert hashlib.sha256(stale.read_bytes()).hexdigest() == "8b03fa714304b34a7f19dc9b077d8fbd54e7f7bc46232bf8d5bc65ae7b873ff5"


def test_lifecycle_seal_unchanged() -> None:
    seal = HERE.parent / "task26-live-lifecycle-evidence-seal-4a6c7ee5-st_01a00e44/SEAL.json"
    assert hashlib.sha256(seal.read_bytes()).hexdigest() == "50e7556e58a876d8136fbfb2023ede8bcb46ac816d97d4b85e1d0559f463d008"


def test_controller_is_not_world_writable() -> None:
    assert os.stat(HERE / "cleanup_controller.py").st_mode & 0o002 == 0
