#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.12,<3.14"
# ///
"""Validate the sealed one-use NutriCoach v1.5 upgrade package without writes."""

from __future__ import annotations
import argparse
import subprocess
import sys
from datetime import UTC, datetime
from pathlib import Path

sys.path.insert(0, str(Path(__file__).resolve().parents[1]))

from scripts.nutricoach_v150_live_upgrade_boundary import (
    clean_boundary as clean_boundary,
)
from scripts.nutricoach_v150_live_upgrade_common import (
    JsonValue as JsonValue,
    LiveTarget as LiveTarget,
    ServiceReader,
    UpgradeDenied as UpgradeDenied,
    canonical,
    load_object as load_object,
    object_at as object_at,
    sha256_bytes,
    sha256_file,
    string_at,
)
from scripts.nutricoach_v150_live_upgrade_state import (
    contract_snapshot,
    profiles_snapshot,
    service_state,
)


def _target(payload: dict[str, JsonValue]) -> LiveTarget:
    value = object_at(payload.get("target"), "target")
    return LiveTarget(
        Path(string_at(value.get("profile_root"), "profile_root")),
        Path(string_at(value.get("profiles_root"), "profiles_root")),
        string_at(value.get("service_name"), "service_name"),
        Path(string_at(value.get("unit_file"), "unit_file")),
        Path(string_at(value.get("dropin_dir"), "dropin_dir")),
    )


def inspect_package(
    package_path: Path,
    candidate_manifest: Path | None = None,
    approval: str | None = None,
    service_reader: ServiceReader = service_state,
    now: datetime | None = None,
    expected_controller_derivation: str | None = None,
) -> dict[str, JsonValue]:
    awaiting = load_object(package_path.with_name("awaiting-authorization.json"))
    if sha256_file(package_path) != awaiting.get("package_sha256"):
        raise UpgradeDenied("package_tamper")
    package = load_object(package_path)
    payload = object_at(package.get("payload"), "payload")
    if (
        expected_controller_derivation is not None
        and payload.get("controller_derivation_sha256")
        != expected_controller_derivation
    ):
        raise UpgradeDenied("controller_derivation")
    digest = sha256_bytes(canonical(payload))
    phrase = f"AUTHORIZE NUTRICOACH V1.5 LIVE UPGRADE {digest}"
    if digest != package.get("package_digest") or phrase != package.get(
        "approval_phrase"
    ):
        raise UpgradeDenied("package_tamper")
    for raw_path, raw_digest in object_at(payload.get("evidence"), "evidence").items():
        if sha256_file(Path(raw_path)) != string_at(raw_digest, "evidence_digest"):
            raise UpgradeDenied("evidence_tamper")
    manifest_path = candidate_manifest or Path(
        string_at(payload.get("candidate_manifest"), "candidate_manifest")
    )
    manifest = load_object(manifest_path)
    if sha256_file(manifest_path) != payload.get(
        "candidate_manifest_sha256"
    ) or manifest.get("candidate_digest") != payload.get("candidate_digest"):
        raise UpgradeDenied("old_or_wrong_candidate")
    if package_path.with_name("authorization-consumed.json").exists():
        raise UpgradeDenied("authorization_already_used")
    if approval is not None and approval != phrase:
        raise UpgradeDenied("wrong_approval")
    target = _target(payload)
    snapshots = object_at(payload.get("snapshots"), "snapshots")
    if profiles_snapshot(target).get("stable_digest") != snapshots.get(
        "stable_after_digest"
    ):
        raise UpgradeDenied("stale_protected_bytes")
    if contract_snapshot(target).get("digest") != snapshots.get(
        "contract_after_digest"
    ):
        raise UpgradeDenied("stale_protected_bytes")
    if service_reader(target.service_name) != snapshots.get("service_after"):
        raise UpgradeDenied("service_state_drift")
    _ = clean_boundary(target.profile_root, now or datetime.now(UTC))
    return {
        "approval_phrase": phrase,
        "candidate_digest": payload["candidate_digest"],
        "package_digest": digest,
        "status": "AUTHORIZATION_VALID_DRY_RUN"
        if approval is not None
        else "AWAITING_AUTHORIZATION",
    }


def main() -> int:
    parser = argparse.ArgumentParser(description=__doc__)
    _ = parser.add_argument("--package", required=True, type=Path)
    _ = parser.add_argument("--candidate-manifest", type=Path)
    _ = parser.add_argument("--approval")
    _ = parser.add_argument("--dry-run", required=True, action="store_true")
    _ = parser.parse_args()
    package = Path(sys.argv[sys.argv.index("--package") + 1])
    candidate_manifest = (
        Path(sys.argv[sys.argv.index("--candidate-manifest") + 1])
        if "--candidate-manifest" in sys.argv
        else None
    )
    approval = (
        sys.argv[sys.argv.index("--approval") + 1] if "--approval" in sys.argv else None
    )
    try:
        result = inspect_package(package, candidate_manifest, approval)
    except (OSError, subprocess.CalledProcessError, UpgradeDenied) as exc:
        print(f"DENIED:{exc}", file=sys.stderr)
        return 2
    print(canonical(result).decode())
    return 0


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