"""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-r21"
BASE_MANIFEST = Path(
    "/home/cube/projects/richard/.worktrees/nutricoach-v150-combined/"
    + ".omo/evidence/nutricoach-v150-combined/task-1-candidate/inputs/"
    + "base-manifest.json"
)
REQUIRED = {
    "gateway/platforms/task26_candidate_authority.py",
    "gateway/platforms/task26_runtime_authority.py",
    "scripts/nutricoach_v150_concrete_host.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)
    payload = _mapping(package.get("payload"), "payload")
    package_digest = _text(package.get("package_digest"), "package_digest")
    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()
    ):
        raise VerificationDenied("package_binding")
    candidate_root = Path(
        _text(target.get("candidate_manifest"), "candidate_manifest")
    ).parent
    candidate = verify_candidate(
        BASE_MANIFEST,
        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 any(
            isinstance(row, dict)
            and row.get("package_digest")
            == "c88bf7cd6354ae36222e7057af5d227a6a966c58d896cb8de994313cd79bea84"
            and row.get("approval_phrase_reusable") is False
            for row in rows
        )
    ):
        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())
