#!/usr/bin/env python3
from __future__ import annotations
import hashlib
import json
import os
import stat
from pathlib import Path

HERE = Path(__file__).parent
PARENT = HERE.parent
CANDIDATE = "2e0894eac92bc396cc4723bf1f18ebc653b95018dd41574df435941c235da925"
WHEEL = "af4a9d0a1ffffb6eb7551c1d6dc2b32853ca6d024332a4f8f5702bbf992f141b"
PLAN = "7ace03c6dad33d2fc3ef223621cbca68a150fde8429932138e252fb8498ac582"


def sha(p: Path) -> str:
    return hashlib.sha256(p.read_bytes()).hexdigest()


def load(n: str):
    return json.loads((HERE / n).read_text())


def check(v: bool, m: str):
    if not v:
        raise RuntimeError(m)


def main() -> int:
    controller = HERE / "cleanup_controller.py"
    contract = HERE / "schema-contract-v2.json"
    permission = HERE / "permission-seal-v2.json"
    fixture = load("fixture-manifest.json")
    tests = load("test-receipt.json")
    live = load("live-pre-rehearsal-dry-run-receipt.json")
    for p in [
        controller,
        contract,
        permission,
        HERE / "fixture-manifest.json",
        HERE / "test-receipt.json",
        HERE / "live-pre-rehearsal-dry-run-receipt.json",
    ]:
        s = p.lstat()
        check(
            stat.S_ISREG(s.st_mode)
            and s.st_nlink == 1
            and s.st_uid == os.getuid()
            and stat.S_IMODE(s.st_mode) in {0o600, 0o700},
            f"unsafe {p}",
        )
    expected = {
        "schema": "task26-post-lifecycle-cleanup-permission-v2",
        "approval": "TASK26_POST_LIFECYCLE_ARCHIVE_CLEANUP_APPROVED",
        "candidate_digest": CANDIDATE,
        "wheel_sha256": WHEEL,
        "plan_sha256": PLAN,
        "actor_id": "8527916639",
        "controller_sha256": sha(controller),
        "contract_sha256": sha(contract),
        "execute_allowed": True,
        "lifecycle_binding": "derive_unique_active_and_seal_in_archive",
    }
    check(load("permission-seal-v2.json") == expected, "permission mismatch")
    c = load("schema-contract-v2.json")
    check(
        c["schema"] == "task26-post-lifecycle-cleanup-contract-v2"
        and c["candidate_digest"] == CANDIDATE,
        "contract mismatch",
    )
    check(
        "post-lifecycle-cleanup-archives" in c["protected_data_roots"]
        and "rehearsal-reset-archives" in c["protected_data_roots"],
        "archive protection",
    )
    for row in fixture["entries"]:
        p = HERE / "fixtures/success" / row["path"]
        check(
            p.stat().st_size == row["size"] and sha(p) == row["sha256"],
            f"fixture drift {row['path']}",
        )
    ledger = json.loads(
        (
            HERE
            / "fixtures/success/data/onboarding/telegram-customer-bootstrap-v1/ledger.json"
        ).read_text()
    )
    check(
        sum(x["state"] == "ACTIVE" for x in ledger["sessions"]) == 1,
        "fixture active count",
    )
    source = controller.read_text()
    check(
        source.index("os.rename(pending, final)")
        < source.index("for s in ss:\n                move(root, s, quarantine)"),
        "clear precedes archive commit",
    )
    for token in [
        "requires exactly one authorized ACTIVE lifecycle",
        "sent_audited",
        "delivery/provider outcome is not terminal sent_audited",
        "claim/lease/attempt authority remains",
        "archive_committed_before_clear",
        "active_ledger_byte_for_byte",
        "rollback(root, moved, quarantine)",
        "restore_or_prepopulate",
    ]:
        check(token in source, f"missing safety token {token}")
    check(
        "transition" not in source and 'ACTIVE" =' not in source,
        "fake terminal transition surface",
    )
    check(
        tests["status"] == "PASS"
        and tests["passed"] == 21
        and tests["failed"] == 0
        and tests["ruff"] == "PASS"
        and tests["lsp_errors"] == 0,
        "tests",
    )
    check(
        live
        == {
            "schema": "task26-post-lifecycle-cleanup-live-dry-run-v2",
            "status": "EXPECTED_REJECTION_PASS",
            "mode": "dry-run",
            "exit_code": 2,
            "reason": "requires exactly one authorized ACTIVE lifecycle",
            "active_lifecycle_count": 0,
            "mutations": 0,
            "archive_created": False,
            "stderr_sha256": sha(HERE / "live-pre-rehearsal-dry-run.stderr"),
        },
        "live rejection",
    )
    preserved = {
        "controller": sha(PARENT / "reset_controller.py"),
        "contract": sha(PARENT / "schema-contract.json"),
        "permission": sha(PARENT / "permission-receipt.json"),
        "delivery_receipt": sha(PARENT / "delivery-receipt.json"),
        "readiness_receipt": sha(
            PARENT / "live-reset-readiness-after-batch-permission-repair.json"
        ),
    }
    check(
        preserved
        == {
            "controller": "bd051dda8666ce9e014ec79c58acd4d7b8df2c27fad01a7a78c76e46c3388baf",
            "contract": "4128cece087f3f4eb84c3917207299fae6bd1ac9971d7e4e8676549106bb7c20",
            "permission": "8a290b11cac5b6957c772366abe875c7f635b8a3e7956a665471ffaa90b6c495",
            "delivery_receipt": "082b03d1cf521f3861017549a976bdcc1db69c75e05903a892d5bd2239aae7c3",
            "readiness_receipt": "776e90301a63dce8912bf8a4110cd037f833c3a0e875a3ddd1289c0c9ee2ac9e",
        },
        "pre-reset evidence changed",
    )
    receipt = {
        "schema": "task26-post-lifecycle-cleanup-independent-verification-v2",
        "status": "PASS",
        "controller_sha256": sha(controller),
        "contract_sha256": sha(contract),
        "permission_sha256": sha(permission),
        "fixture_manifest_sha256": sha(HERE / "fixture-manifest.json"),
        "test_receipt_sha256": sha(HERE / "test-receipt.json"),
        "live_dry_run_receipt_sha256": sha(
            HERE / "live-pre-rehearsal-dry-run-receipt.json"
        ),
        "pre_reset_artifacts_immutable": True,
        "archive_commit_before_clear": True,
        "active_row_preserved_in_byte_exact_ledger": True,
        "ready_for_post_lifecycle_cleanup": True,
    }
    print(json.dumps(receipt, sort_keys=True, separators=(",", ":")))
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
