"""Read-only verifier for the fresh V15 runtime-authority preseal."""

from __future__ import annotations

import hashlib
import json
import stat
from pathlib import Path

from pydantic import JsonValue, TypeAdapter

from gateway.platforms.task26_runtime_authority import (
    build_runtime_authority_pin,
)
from scripts.nutricoach_v150_detached_bootstrap import (
    verify_closure,
    verify_package_inventory,
)
from scripts.nutricoach_v150_live_upgrade_common import canonical
from scripts.nutricoach_v150_runtime_ops import dependency_snapshot_digest
from scripts.verify_nutricoach_v150_candidate import verify as verify_candidate

_OBJECT = TypeAdapter(dict[str, JsonValue])
ROOT = Path("/home/cube/.hermes/migrations/nutricoach-v1.5.0-combined")
PRESEAL = ROOT / "live-transaction-preseal-v15-runtime-authority-r71b-maintenance"
REQUIRED = {
    "gateway/platforms/task26_candidate_authority.py",
    "gateway/platforms/task26_runtime_authority.py",
    "scripts/nutricoach_v150_concrete_host.py",
    "scripts/nutricoach_v150_r71b_cron_watch.py",
    "scripts/nutricoach_v150_r71b_maintenance_confirmation.py",
    "scripts/nutricoach_v150_r71b_maintenance_host.py",
    "scripts/nutricoach_v150_r71b_maintenance_transaction.py",
    "scripts/nutricoach_v150_r71b_package.py",
    "scripts/nutricoach_v150_r71b_preparation.py",
    "scripts/nutricoach_v150_r71b_preseal_arguments.py",
    "scripts/nutricoach_v150_r71b_preseal_verifier.py",
    "scripts/nutricoach_v150_r71b_sealed_host.py",
    "scripts/nutricoach_v150_rollback_guard.py",
    "scripts/nutricoach_v150_host_operations.py",
    "scripts/nutricoach_v150_sealed_controller.py",
    "scripts/prepare_nutricoach_v150_v15_preseal.py",
    "scripts/verify_nutricoach_v150_preseal_v15.py",
    "tests/test_nutricoach_v150_v15_authority_adversarial.py",
    "tests/test_nutricoach_v150_v15_safety.py",
}


class VerificationDenied(RuntimeError):
    """Fail-closed V15 preseal denial."""


def _load(path: Path) -> dict[str, JsonValue]:
    return _OBJECT.validate_json(path.read_bytes())


def _text(value: JsonValue | None, label: str) -> str:
    if not isinstance(value, str):
        raise VerificationDenied(label)
    return value


def _mapping(value: JsonValue | None, label: str) -> dict[str, JsonValue]:
    if not isinstance(value, dict):
        raise VerificationDenied(label)
    return value


def verify() -> dict[str, JsonValue]:
    verify_package_inventory(PRESEAL / "package-manifest.json", PRESEAL)
    for path in (PRESEAL, *PRESEAL.rglob("*")):
        info = path.stat(follow_symlinks=False)
        if path.is_symlink() or stat.S_IMODE(info.st_mode) & 0o222:
            raise VerificationDenied("immutable_tree")
        if path.is_file() and info.st_nlink != 1:
            raise VerificationDenied("immutable_hardlink")
        if path.suffix in {".pyc", ".pyo"} or "__pycache__" in path.parts:
            raise VerificationDenied("immutable_bytecode")
    closure_document = _load(PRESEAL / "controller-source-manifest.json")
    files = _mapping(closure_document.get("files"), "closure_files")
    if not REQUIRED.issubset(files):
        raise VerificationDenied("closure_incomplete")
    closure_digest = verify_closure(
        PRESEAL / "controller-source-manifest.json",
        PRESEAL / "controller-source",
    )
    target = _load(PRESEAL / "sealed-target.json")
    package_path = Path(_text(target.get("permission_package"), "package"))
    package = _load(package_path)
    if package.get("schema") == "nutricoach-v150-r71b-permission-package-v1":
        from scripts.nutricoach_v150_r71b_preseal_verifier import verify_r71b_preseal

        result = verify_r71b_preseal(PRESEAL / "sealed-target.json")
        return {
            **result,
            "candidate_digest": _text(target.get("candidate_digest"), "candidate"),
            "closure_digest": closure_digest,
            "status": "R71B_MAINTENANCE_PRESEAL_VERIFIED",
        }
    payload = _mapping(package.get("payload"), "payload")
    target_binding = _mapping(payload.get("target_binding"), "target_binding")
    package_digest = _text(package.get("package_digest"), "package_digest")
    controller_derivation = hashlib.sha256(canonical(files)).hexdigest()
    if (
        hashlib.sha256(canonical(payload)).hexdigest() != package_digest
        or package.get("approval_phrase")
        != f"AUTHORIZE NUTRICOACH V1.5 LIVE UPGRADE {package_digest}"
        or target.get("package_digest") != package_digest
        or target.get("permission_package_sha256")
        != hashlib.sha256(package_path.read_bytes()).hexdigest()
        or any(target.get(key) != value for key, value in target_binding.items())
        or payload.get("candidate_digest") != target.get("candidate_digest")
        or payload.get("authority_baseline") != target.get("authority_baseline")
        or payload.get("wheels") != target.get("wheels")
        or payload.get("controller_derivation_sha256")
        != controller_derivation
        or target.get("controller_derivation_sha256")
        != controller_derivation
    ):
        raise VerificationDenied("package_binding")
    package_manifest = _load(PRESEAL / "package-manifest.json")
    if (
        package_manifest.get("new_package_digest") != package_digest
        or package_manifest.get("new_approval_phrase")
        != package.get("approval_phrase")
        or package_manifest.get("self_exclusion")
        != "package-manifest.json only"
    ):
        raise VerificationDenied("package_manifest")
    candidate_root = Path(
        _text(target.get("candidate_manifest"), "candidate_manifest")
    ).parent
    candidate = verify_candidate(
        candidate_root / "inputs/base-manifest.json",
        candidate_root,
        candidate_root / "manifest.json",
    )
    if target.get("candidate_digest") != candidate:
        raise VerificationDenied("candidate_binding")
    dependency = Path(_text(target.get("dependency_snapshot"), "dependency"))
    if dependency_snapshot_digest(dependency) != target.get(
        "dependency_snapshot_sha256"
    ):
        raise VerificationDenied("dependency_binding")
    baseline = _mapping(target.get("authority_baseline"), "authority_baseline")
    authority_root = Path(_text(baseline.get("authority_root"), "authority_root"))
    current_pin = build_runtime_authority_pin(authority_root)
    for key in (
        "source_id",
        "genesis_sha256",
        "registry_head_sha256",
        "ledger_head_sha256",
        "event_count",
    ):
        if baseline.get(key) != current_pin.get(key):
            raise VerificationDenied("authority_baseline")
    for key in ("global_approval_ledger", "execution_root"):
        if Path(_text(target.get(key), key)).exists():
            raise VerificationDenied("authority_root_exists")
    if Path(_text(target.get("successor_runtime"), "successor")).parent.exists():
        raise VerificationDenied("successor_exists")
    supersession = _load(PRESEAL / "package-supersession.json")
    rows = supersession.get("superseded")
    if (
        supersession.get("active_package_digest") != package_digest
        or not isinstance(rows, list)
        or not {
            "c88bf7cd6354ae36222e7057af5d227a6a966c58d896cb8de994313cd79bea84",
            "0225ccab282b19648f5ac7984725f1d347c887068ef75fd705272c9c8d7c6e7f",
            "2226bc45217a2b9e1b517a153a5f88ba958b1a866ec589273580a39354cc2807",
            "cd4c2365fbc10366a67e70c3cb7b85320f42b88557d2b712d1f28e6a99502d74",
            "3360d0dc45f082eb78b32139080470695cbd5620d4c81d3b00e15b01b579709e",
            "d1e4fa3908f8aaf4c0319d6ebfaeff1fc4cf2e772f2c3bd41774e5003fe86b09",
            "b8dd778c763b138a5ee053b80008d065fa964e3c4f5a5555c4ca63c577c610a8",
            "1042472df214a1076f11fd1eb102f6c456d97ae8fcc085f8d811cf885bcf246f",
            "8d5ec1a3a551a143cf12f7086033bf96c91f1e7e1eb55858ed8a8c2398d1c89a",
            "2e1c037b1931d324133e1ac9e76dabbf1accdcf1fd809f635712c3fd25e3bc82",
            "ac192b3f7e5683075db899ef6f5fb33f1be9dfc10f9d98381be5f4f70ed4d684",
            "ebc6f9109c15527903e200e6d41f763340e41989b6b6d7978c8bcc35353d0d7c",
            "91b4b138aa993f186a61f1763b26850d3d7be00d8d03f5e40248e5f028637e9a",
            "f00911239319f4888c255aef75190550f34b7e69ef3cdb28568664ec6aa87e4c",
            "791aaa4f85ac4475591741a315d3265c215f0667f4ab742fb89c539786de09b0",
            "689f664992509f7e77dfa2a0282096382a5562a0058c1794146cf8776b0babb3",
            "010caa3f8848903881609876a8bb03ada55ae00bd38851fdb9c3fa3745f70d92",
            "8c2814aa6e3b9c9ad44742f4f8336170e56c87d489ad1a6ce2b18105a62b8b72",
            "75e9a4fbffa008e9137bd9c3785c8c8183e80cebef4ddcdf565548d11693f6b8",
            "d80b65b9263ed7501941fdcf370b94a8e676968964cb4abb0408b12712f93d02",
            "4c7ba03776f4af6ddd86297920da94c920b0da6fe36c978334d174638cd4446f",
            "eda7e573a01bc7e0bb44ff34fe4dabee5d3f8086bec6f0932a378ae0df248088",
            "5455da43af21b9ba7458d91ffef897bd55097ee30498cc8b652ec9e6b237ad8d",
            "ff98e8804ecf421397266a378944e1abcc3c6fba4e510f52025c586c9a362116",
        }.issubset({
            str(row.get("package_digest"))
            for row in rows
            if isinstance(row, dict) and row.get("approval_phrase_reusable") is False
        })
    ):
        raise VerificationDenied("r20_supersession")
    return {
        "approval_phrase": package["approval_phrase"],
        "candidate_digest": candidate,
        "closure_digest": closure_digest,
        "package_digest": package_digest,
        "package_sha256": hashlib.sha256(package_path.read_bytes()).hexdigest(),
        "status": "V15_RUNTIME_AUTHORITY_PRESEAL_VERIFIED",
    }


def main() -> int:
    try:
        result = verify()
    except (OSError, ValueError, VerificationDenied) as error:
        print(f"DENIED:{error}")
        return 2
    print(json.dumps(result, sort_keys=True, separators=(",", ":")))
    return 0


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