#!/usr/bin/env python3
"""Validate retained approval evidence before a one-machine customer pilot."""

from __future__ import annotations

import argparse
import hashlib
import json
import sys
from pathlib import Path
from typing import Any


TOOL_NAME = "legacy-windows-first-iteration-pilot-readiness"
APPROVAL_SCHEMA = "legacy-windows-first-iteration-pilot-approval"
CHECKLIST_SCHEMA = "legacy-windows-first-iteration-pilot-checklist"
FINAL_SUMMARY_SCHEMA = "legacy-windows-first-iteration-final-summary"
REQUIRED_ITEM_KEYS = {
    "windows_7_sp1_lab_evidence",
    "server_2008_r2_sp1_lab_evidence",
    "final_summary_hash_sidecar",
    "win10_bridge_media_url_redacted",
    "customer_machine_selected",
    "customer_scoped_enablement_approved",
    "backup_or_image_rollback_confirmed",
    "vendor_software_reviewed",
    "clinical_equipment_reviewed",
    "customer_approval_recorded",
}
PRE_APPROVAL_PASSED_ITEM_KEYS = {
    "windows_7_sp1_lab_evidence",
    "server_2008_r2_sp1_lab_evidence",
    "final_summary_hash_sidecar",
    "win10_bridge_media_url_redacted",
}
PRE_APPROVAL_PENDING_ITEM_KEYS = REQUIRED_ITEM_KEYS - PRE_APPROVAL_PASSED_ITEM_KEYS
REQUIRED_APPROVAL_FIELDS = {
    "approval_ticket",
    "backup_evidence",
    "clinical_equipment_review",
    "customer",
    "customer_approval",
    "customer_scoped_enablement",
    "operator",
    "pilot_hostname",
    "rollback_plan",
    "vendor_software_review",
}
APPROVAL_ITEM_EVIDENCE_FIELDS = {
    "backup_or_image_rollback_confirmed": "backup_evidence",
    "clinical_equipment_reviewed": "clinical_equipment_review",
    "customer_approval_recorded": "customer_approval",
    "customer_machine_selected": "pilot_hostname",
    "customer_scoped_enablement_approved": "customer_scoped_enablement",
    "vendor_software_reviewed": "vendor_software_review",
}
REQUIRED_FINAL_SMOKE_CHECKS = {
    "peer_recover",
    "process:sk-agent-legacy",
    "process:sk-tray",
    "recover_health",
    "self_rescue",
    "watchdog.log",
}
LAB_EVIDENCE_ITEM_KEYS = {
    "windows_7_sp1_lab_evidence",
    "server_2008_r2_sp1_lab_evidence",
    "win10_bridge_media_url_redacted",
}
REQUIRED_PRE_APPROVAL_EVIDENCE_ITEM_KEYS = LAB_EVIDENCE_ITEM_KEYS | {
    "final_summary_hash_sidecar",
}
PLACEHOLDER_APPROVAL_EVIDENCE = {
    "na",
    "none",
    "pending",
    "placeholder",
    "tbd",
    "todo",
    "unknown",
}


def _is_placeholder_approval_evidence(value: str) -> bool:
    text = value.strip().lower()
    normalized = "".join(char for char in text if char.isalnum())
    return text in PLACEHOLDER_APPROVAL_EVIDENCE or normalized in PLACEHOLDER_APPROVAL_EVIDENCE


def _sha256(path: Path) -> str:
    h = hashlib.sha256()
    with path.open("rb") as f:
        for chunk in iter(lambda: f.read(1024 * 1024), b""):
            h.update(chunk)
    return h.hexdigest()


def _is_sha256_hex(value: str) -> bool:
    if len(value) != 64:
        return False
    try:
        int(value, 16)
    except ValueError:
        return False
    return True


def _load_json(path: Path) -> tuple[dict[str, Any] | None, str | None]:
    try:
        payload = json.loads(path.read_text(encoding="utf-8"))
    except Exception as exc:
        return None, f"{path}: cannot read JSON: {exc}"
    if not isinstance(payload, dict):
        return None, f"{path}: root JSON value must be an object"
    return payload, None


def _validate_sidecar(path: Path, label: str) -> list[str]:
    sidecar = path.with_suffix(path.suffix + ".sha256")
    if not sidecar.exists():
        return [f"{label} checksum sidecar is missing: {sidecar}"]
    try:
        parts = sidecar.read_text(encoding="utf-8").strip().split()
    except Exception as exc:
        return [f"{label} checksum sidecar cannot be read: {exc}"]
    if not parts:
        return [f"{label} checksum sidecar cannot be read: empty sidecar"]
    expected = parts[0]
    if len(parts) < 2:
        return [f"{label} checksum sidecar filename is missing"]
    if len(parts) > 2:
        return [f"{label} checksum sidecar must contain exactly sha256 and filename"]
    if parts[1] != path.name:
        return [f"{label} checksum sidecar filename mismatch"]
    if not _is_sha256_hex(expected):
        return [f"{label} checksum sidecar SHA-256 is malformed"]
    actual = _sha256(path)
    if expected != actual:
        return [f"{label} checksum sidecar mismatch"]
    return []


def _resolve_recorded_path(recorded: str, base: Path) -> Path:
    path = Path(recorded)
    if path.is_absolute():
        return path
    return base / path


def _same_windows_hostname(left: str, right: str) -> bool:
    return left.strip().lower() == right.strip().lower()


def _is_windows_computer_name(value: str) -> bool:
    text = value.strip()
    if len(text) < 1 or len(text) > 15:
        return False
    if text[0] == "-" or text[-1] == "-":
        return False
    return all(
        ("A" <= char <= "Z")
        or ("a" <= char <= "z")
        or ("0" <= char <= "9")
        or char == "-"
        for char in text
    )


def _duplicate_item_keys(items: list[Any]) -> list[str]:
    seen: set[str] = set()
    duplicates: set[str] = set()
    for item in items:
        if not isinstance(item, dict):
            continue
        key = str(item.get("key") or "")
        if not key:
            continue
        if key in seen:
            duplicates.add(key)
        seen.add(key)
    return sorted(duplicates)


def _unknown_item_keys(items: list[Any]) -> list[str]:
    keys = {
        str(item.get("key") or "")
        for item in items
        if isinstance(item, dict) and str(item.get("key") or "")
    }
    return sorted(keys - REQUIRED_ITEM_KEYS)


def _validate_checklist_item_entries(path: Path, items: list[Any]) -> list[str]:
    if any(not isinstance(item, dict) for item in items):
        return [f"{path.name}: checklist item entries must be objects"]
    return []


def _validate_checklist_item_keys(path: Path, items: list[Any]) -> list[str]:
    errors: list[str] = []
    for item in items:
        if not isinstance(item, dict):
            continue
        if "key" not in item or item.get("key") is None:
            errors.append(f"{path.name}: checklist item key is required")
            continue
        key = item.get("key")
        if not isinstance(key, str):
            errors.append(f"{path.name}: checklist item key must be a string")
        elif not key.strip():
            errors.append(f"{path.name}: checklist item key is required")
    return errors


def _validate_checklist_item_status_types(path: Path, items: list[Any]) -> list[str]:
    errors: list[str] = []
    for item in items:
        if not isinstance(item, dict):
            continue
        key = str(item.get("key") or "")
        if "status" in item and not isinstance(item.get("status"), str):
            errors.append(f"{path.name}: checklist item {key} status must be a string")
    return errors


def _validate_approval_item_entries(path: Path, items: list[Any]) -> list[str]:
    if any(not isinstance(item, dict) for item in items):
        return [f"{path.name}: approval item entries must be objects"]
    return []


def _validate_approval_item_keys(path: Path, items: list[Any]) -> list[str]:
    errors: list[str] = []
    for item in items:
        if not isinstance(item, dict):
            continue
        if "key" not in item or item.get("key") is None:
            errors.append(f"{path.name}: approval item key is required")
            continue
        key = item.get("key")
        if not isinstance(key, str):
            errors.append(f"{path.name}: approval item key must be a string")
        elif not key.strip():
            errors.append(f"{path.name}: approval item key is required")
    return errors


def _validate_approval_item_evidence_types(path: Path, items: dict[str, dict[str, Any]]) -> list[str]:
    errors: list[str] = []
    for key, item in items.items():
        if "evidence" in item and not isinstance(item.get("evidence"), str):
            errors.append(f"{path.name}: approval item {key} evidence must be a string")
    return errors


def _validate_approval_item_status_types(path: Path, items: list[Any]) -> list[str]:
    errors: list[str] = []
    for item in items:
        if not isinstance(item, dict):
            continue
        key = str(item.get("key") or "")
        if "status" in item and not isinstance(item.get("status"), str):
            errors.append(f"{path.name}: approval item {key} status must be a string")
    return errors


def _validate_checklist_item_evidence_types(path: Path, items: list[Any]) -> list[str]:
    errors: list[str] = []
    for item in items:
        if not isinstance(item, dict):
            continue
        key = str(item.get("key") or "")
        if "evidence" in item and not isinstance(item.get("evidence"), str):
            errors.append(f"{path.name}: checklist item {key} evidence must be a string")
    return errors


def _validate_required_lab_evidence(path: Path, items: list[Any]) -> list[str]:
    errors: list[str] = []
    for item in items:
        if not isinstance(item, dict):
            continue
        key = str(item.get("key") or "")
        if key not in REQUIRED_PRE_APPROVAL_EVIDENCE_ITEM_KEYS:
            continue
        evidence = item.get("evidence")
        if evidence is None or (isinstance(evidence, str) and not evidence.strip()):
            errors.append(f"{path.name}: checklist item {key} evidence is required")
    return errors


def _validate_pending_checklist_item_evidence(path: Path, items: list[Any]) -> list[str]:
    errors: list[str] = []
    for item in items:
        if not isinstance(item, dict):
            continue
        key = str(item.get("key") or "")
        if key not in PRE_APPROVAL_PENDING_ITEM_KEYS:
            continue
        evidence = item.get("evidence")
        if isinstance(evidence, str) and evidence.strip():
            errors.append(f"{path.name}: checklist item {key} evidence must be empty before approval")
    return errors


def _validate_final_platform(
    path: Path,
    platform: dict[str, Any],
    expected_build_manifest_sha: str = "",
) -> list[str]:
    errors: list[str] = []
    os_kind = str(platform.get("os_kind") or "")
    raw_hostname = platform.get("hostname")
    hostname = raw_hostname.strip() if isinstance(raw_hostname, str) else ""
    label = hostname
    if not isinstance(raw_hostname, str):
        label = os_kind or "unknown"
        errors.append(f"{label}: final summary platform hostname must be a string")
    elif not hostname:
        label = os_kind or "unknown"
        errors.append(f"{label}: final summary platform hostname is required")

    bundle_text = str(platform.get("bundle") or "").strip()
    if not bundle_text:
        errors.append(f"{label}: final summary platform bundle is required")
    else:
        bundle = _resolve_recorded_path(bundle_text, path.parent)
        if not bundle.exists():
            errors.append(f"{label}: final summary platform bundle is missing: {bundle}")
        else:
            expected_sha = str(platform.get("sha256") or "").strip()
            if not expected_sha:
                errors.append(f"{label}: final summary platform sha256 is required")
            elif not _is_sha256_hex(expected_sha):
                errors.append(f"{label}: final summary platform sha256 is malformed")
            elif expected_sha != _sha256(bundle):
                errors.append(f"{label}: final summary platform sha256 mismatch")
            raw_platform_size = platform.get("size_bytes")
            expected_size = (
                raw_platform_size
                if isinstance(raw_platform_size, int) and not isinstance(raw_platform_size, bool)
                else 0
            )
            if expected_size <= 0:
                errors.append(f"{label}: final summary platform size_bytes is required")
            elif expected_size != bundle.stat().st_size:
                errors.append(f"{label}: final summary platform size_bytes mismatch")

    collector = platform.get("collector")
    if not isinstance(collector, dict):
        collector = {}
        errors.append(f"{label}: final summary platform collector proof is required")
    for key in ("collector_exit", "smoke_exit"):
        value = collector.get(key)
        if isinstance(value, bool) or not isinstance(value, int) or value != 0:
            errors.append(f"{label}: final summary collector {key} must be 0")
    raw_files_count = collector.get("files_count")
    files_count = (
        raw_files_count
        if isinstance(raw_files_count, int) and not isinstance(raw_files_count, bool)
        else 0
    )
    if files_count <= 0:
        errors.append(f"{label}: final summary collector files_count is required")
    collector_build_manifest_sha = str(collector.get("build_manifest_sha256") or "").strip()
    if not collector_build_manifest_sha:
        errors.append(f"{label}: final summary collector build_manifest_sha256 is required")
    elif not _is_sha256_hex(collector_build_manifest_sha):
        errors.append(f"{label}: final summary collector build_manifest_sha256 is malformed")
    elif expected_build_manifest_sha and collector_build_manifest_sha != expected_build_manifest_sha:
        errors.append(f"{label}: final summary collector build_manifest_sha256 mismatch")

    operator_context = platform.get("operator_context")
    if not isinstance(operator_context, dict):
        operator_context = {}
        errors.append(f"{label}: final summary operator_context proof is required")
    if operator_context.get("is_elevated") is not True:
        errors.append(f"{label}: final summary operator_context is_elevated must be true")
    raw_operator_computer_name = operator_context.get("computer_name")
    operator_computer_name = (
        raw_operator_computer_name.strip()
        if isinstance(raw_operator_computer_name, str)
        else ""
    )
    if not isinstance(raw_operator_computer_name, str):
        errors.append(f"{label}: final summary operator_context computer_name must be a string")
    elif hostname and not _same_windows_hostname(operator_computer_name, hostname):
        errors.append(f"{label}: final summary operator_context computer_name must match hostname")

    smoke_checks = platform.get("smoke_checks")
    if not isinstance(smoke_checks, dict):
        smoke_checks = {}
        errors.append(f"{label}: final summary smoke_checks proof is required")
    for check in sorted(REQUIRED_FINAL_SMOKE_CHECKS):
        if smoke_checks.get(check) is not True:
            errors.append(f"{label}: final summary smoke check {check} must be true")

    win10_probe = platform.get("win10_probe")
    win10_bridge = platform.get("win10_bridge")
    if os_kind == "windows_7_sp1":
        if not isinstance(win10_probe, dict) or win10_probe.get("verdict") != "candidate":
            errors.append(f"{label}: final summary win10_probe verdict must be candidate")
        if not isinstance(win10_bridge, dict):
            win10_bridge = {}
            errors.append(f"{label}: final summary win10_bridge proof is required")
        if win10_bridge.get("acknowledgements_recorded") is not True:
            errors.append(f"{label}: final summary win10_bridge acknowledgements_recorded must be true")
        if win10_bridge.get("evidence_notes_recorded") is not True:
            errors.append(f"{label}: final summary win10_bridge evidence_notes_recorded must be true")
        if win10_bridge.get("media_url_query_redacted") is not True:
            errors.append(f"{label}: final summary win10_bridge media_url_query_redacted must be true")
        if win10_bridge.get("probe_verdict") != "candidate":
            errors.append(f"{label}: final summary win10_bridge probe_verdict must be candidate")
        if win10_bridge.get("setup_launched") is not True:
            errors.append(f"{label}: final summary win10_bridge setup_launched must be true")
    elif os_kind == "server_2008_r2":
        if win10_probe not in ({}, None):
            errors.append(f"{label}: final summary Server 2008 R2 win10_probe must be empty")
        if win10_bridge not in ({}, None):
            errors.append(f"{label}: final summary Server 2008 R2 win10_bridge must be empty")

    return errors


def _validate_final_build_manifest(path: Path, summary: dict[str, Any]) -> list[str]:
    errors: list[str] = []
    build_manifest_text = str(summary.get("build_manifest") or "").strip()
    if not build_manifest_text:
        return [f"{path.name}: build_manifest is required"]
    build_manifest = _resolve_recorded_path(build_manifest_text, path.parent)
    if not build_manifest.exists():
        return [f"{path.name}: build_manifest is missing: {build_manifest}"]

    expected_sha = str(summary.get("build_manifest_sha256") or "").strip()
    if not expected_sha:
        errors.append(f"{path.name}: build_manifest_sha256 is required")
    elif not _is_sha256_hex(expected_sha):
        errors.append(f"{path.name}: build_manifest_sha256 is malformed")
    elif expected_sha != _sha256(build_manifest):
        errors.append(f"{path.name}: build_manifest_sha256 mismatch")
    raw_build_manifest_size = summary.get("build_manifest_size_bytes")
    expected_size = (
        raw_build_manifest_size
        if isinstance(raw_build_manifest_size, int) and not isinstance(raw_build_manifest_size, bool)
        else 0
    )
    if expected_size <= 0:
        errors.append(f"{path.name}: build_manifest_size_bytes is required")
    elif expected_size != build_manifest.stat().st_size:
        errors.append(f"{path.name}: build_manifest_size_bytes mismatch")
    return errors


def _validate_final_summary(path: Path, expected_sha: str) -> tuple[dict[str, Any] | None, list[str]]:
    errors = _validate_sidecar(path, "final summary")
    summary, error = _load_json(path)
    if error:
        errors.append(error)
        return None, errors
    assert summary is not None
    actual_sha = _sha256(path)
    if not expected_sha:
        errors.append(f"{path.name}: final_summary_sha256 is required")
    elif not _is_sha256_hex(expected_sha):
        errors.append(f"{path.name}: final_summary_sha256 is malformed")
    elif expected_sha != actual_sha:
        errors.append("final_summary_sha256 mismatch")
    if summary.get("schema") != FINAL_SUMMARY_SCHEMA:
        errors.append(f"{path.name}: schema is not {FINAL_SUMMARY_SCHEMA}")
    if summary.get("status") != "passed":
        errors.append(f"{path.name}: status must be passed")
    if summary.get("readiness") != "legacy Windows first-iteration readiness passed":
        errors.append(f"{path.name}: readiness status is not passed")
    errors.extend(_validate_final_build_manifest(path, summary))
    expected_build_manifest_sha = str(summary.get("build_manifest_sha256") or "").strip()
    platforms_payload = summary.get("platforms")
    if not isinstance(platforms_payload, list):
        platforms_payload = []
        errors.append(f"{path.name}: platforms must be a list")
    platforms: dict[str, list[dict[str, Any]]] = {}
    platform_hostnames: list[str] = []
    for item in platforms_payload:
        if not isinstance(item, dict):
            errors.append(f"{path.name}: platform entries must be objects")
            continue
        raw_os_kind = item.get("os_kind")
        if not isinstance(raw_os_kind, str):
            errors.append(f"{path.name}: platform os_kind must be a string")
            errors.extend(_validate_final_platform(path, item, expected_build_manifest_sha))
            continue
        os_kind = raw_os_kind.strip()
        if os_kind not in {"windows_7_sp1", "server_2008_r2"}:
            errors.append(f"{path.name}: unknown platform os_kind: {os_kind or '<empty>'}")
            errors.extend(_validate_final_platform(path, item, expected_build_manifest_sha))
            continue
        platforms.setdefault(os_kind, []).append(item)
        raw_hostname = item.get("hostname")
        if isinstance(raw_hostname, str) and raw_hostname.strip():
            hostname = raw_hostname.strip()
            if any(_same_windows_hostname(hostname, existing) for existing in platform_hostnames):
                errors.append(f"{path.name}: duplicate retained lab hostname: {hostname}")
            platform_hostnames.append(hostname)
        errors.extend(_validate_final_platform(path, item, expected_build_manifest_sha))
    if "windows_7_sp1" not in platforms:
        errors.append(f"{path.name}: missing Windows 7 SP1 platform proof")
    if "server_2008_r2" not in platforms:
        errors.append(f"{path.name}: missing Windows Server 2008 R2 SP1 platform proof")
    for os_kind, label in (
        ("windows_7_sp1", "Windows 7 SP1"),
        ("server_2008_r2", "Windows Server 2008 R2 SP1"),
    ):
        if len(platforms.get(os_kind, [])) > 1:
            errors.append(f"{path.name}: duplicate {label} platform proof")
    return summary, errors


def _validate_checklist(path: Path, approval: dict[str, Any]) -> tuple[dict[str, Any] | None, dict[str, Any] | None, list[str]]:
    errors = _validate_sidecar(path, "pilot checklist")
    checklist, error = _load_json(path)
    if error:
        errors.append(error)
        return None, None, errors
    assert checklist is not None
    actual_sha = _sha256(path)
    expected_source_checklist_sha = str(approval.get("source_checklist_sha256") or "").strip()
    if not expected_source_checklist_sha:
        errors.append("source_checklist_sha256 is required")
    elif not _is_sha256_hex(expected_source_checklist_sha):
        errors.append("source_checklist_sha256 is malformed")
    elif expected_source_checklist_sha != actual_sha:
        errors.append("source_checklist_sha256 mismatch")
    if checklist.get("schema") != CHECKLIST_SCHEMA:
        errors.append(f"{path.name}: schema is not {CHECKLIST_SCHEMA}")
    if checklist.get("status") != "lab_passed_customer_approval_required":
        errors.append(f"{path.name}: status must be lab_passed_customer_approval_required")
    if checklist.get("customer_pilot_ready") is not False:
        errors.append(f"{path.name}: customer_pilot_ready must be false before approval")
    checklist_items = checklist.get("items") or []
    if isinstance(checklist_items, list):
        errors.extend(_validate_checklist_item_entries(path, checklist_items))
        errors.extend(_validate_checklist_item_keys(path, checklist_items))
        errors.extend(_validate_checklist_item_status_types(path, checklist_items))
        duplicates = _duplicate_item_keys(checklist_items)
        if duplicates:
            errors.append(f"{path.name}: duplicate pilot checklist item(s): {', '.join(duplicates)}")
        unknown = _unknown_item_keys(checklist_items)
        if unknown:
            errors.append(f"{path.name}: unknown pilot checklist item(s): {', '.join(unknown)}")
        errors.extend(_validate_checklist_item_evidence_types(path, checklist_items))
        errors.extend(_validate_required_lab_evidence(path, checklist_items))
        errors.extend(_validate_pending_checklist_item_evidence(path, checklist_items))
    else:
        checklist_items = []
        errors.append(f"{path.name}: items must be a list")
    items = {
        str(item.get("key") or ""): str(item.get("status") or "")
        for item in checklist_items
        if isinstance(item, dict)
    }
    missing = sorted(REQUIRED_ITEM_KEYS - set(items))
    if missing:
        errors.append(f"{path.name}: missing pilot checklist item(s): {', '.join(missing)}")
    for key in sorted(PRE_APPROVAL_PASSED_ITEM_KEYS):
        if items.get(key) != "passed":
            errors.append(f"{path.name}: checklist item {key} must be passed")
    for key in sorted(PRE_APPROVAL_PENDING_ITEM_KEYS):
        if items.get(key) != "pending":
            errors.append(f"{path.name}: checklist item {key} must be pending before approval")
    final_summary_text = str(checklist.get("final_summary") or "").strip()
    if not final_summary_text:
        final_summary = None
        errors.append(f"{path.name}: final_summary is required")
    else:
        final_summary_path = _resolve_recorded_path(final_summary_text, path.parent)
        final_summary, final_errors = _validate_final_summary(
            final_summary_path,
            str(checklist.get("final_summary_sha256") or ""),
        )
        errors.extend(final_errors)
    if final_summary is not None:
        errors.extend(_validate_checklist_evidence_matches_final_summary(path, checklist_items, final_summary))
        final_summary_path = _resolve_recorded_path(final_summary_text, path.parent)
        errors.extend(_validate_final_summary_sidecar_evidence(path, checklist_items, final_summary_path))
        checklist_build_manifest_sha = str(checklist.get("build_manifest_sha256") or "").strip()
        if not checklist_build_manifest_sha:
            errors.append(f"{path.name}: build_manifest_sha256 is required")
        elif not _is_sha256_hex(checklist_build_manifest_sha):
            errors.append(f"{path.name}: build_manifest_sha256 is malformed")
        elif checklist_build_manifest_sha != final_summary.get("build_manifest_sha256"):
            errors.append("checklist build_manifest_sha256 mismatch")
    return checklist, final_summary, errors


def _validate_pilot_hostname_against_lab_hosts(
    approval: dict[str, Any],
    checklist: dict[str, Any],
    summary: dict[str, Any] | None,
) -> list[str]:
    approval_details = approval.get("approval")
    if not isinstance(approval_details, dict):
        return []
    pilot_hostname = str(approval_details.get("pilot_hostname") or "").strip()
    if not pilot_hostname:
        return []

    lab_hosts: list[str] = []
    for item in checklist.get("items") or []:
        if not isinstance(item, dict):
            continue
        if str(item.get("key") or "") not in LAB_EVIDENCE_ITEM_KEYS:
            continue
        evidence = str(item.get("evidence") or "").strip()
        if evidence:
            lab_hosts.append(evidence)
    if isinstance(summary, dict):
        for platform in summary.get("platforms") or []:
            if not isinstance(platform, dict):
                continue
            if str(platform.get("os_kind") or "") not in {"windows_7_sp1", "server_2008_r2"}:
                continue
            hostname = str(platform.get("hostname") or "").strip()
            if hostname:
                lab_hosts.append(hostname)
    for lab_host in lab_hosts:
        if pilot_hostname.lower() == lab_host.lower():
            return [f"pilot hostname {pilot_hostname} matches retained lab evidence host {lab_host}"]
    return []


def _final_summary_host_by_platform(summary: dict[str, Any]) -> dict[str, str]:
    hosts: dict[str, str] = {}
    platforms = summary.get("platforms")
    if not isinstance(platforms, list):
        return hosts
    for platform in platforms:
        if not isinstance(platform, dict):
            continue
        os_kind = platform.get("os_kind")
        hostname = platform.get("hostname")
        if isinstance(os_kind, str) and isinstance(hostname, str):
            hosts[os_kind.strip()] = hostname.strip()
    return hosts


def _validate_checklist_evidence_matches_final_summary(
    path: Path,
    items: list[Any],
    summary: dict[str, Any] | None,
) -> list[str]:
    if not isinstance(summary, dict):
        return []
    errors: list[str] = []
    host_by_platform = _final_summary_host_by_platform(summary)
    expected_platforms = {
        "windows_7_sp1_lab_evidence": "windows_7_sp1",
        "server_2008_r2_sp1_lab_evidence": "server_2008_r2",
        "win10_bridge_media_url_redacted": "windows_7_sp1",
    }
    for item in items:
        if not isinstance(item, dict):
            continue
        key = str(item.get("key") or "")
        os_kind = expected_platforms.get(key)
        if os_kind is None:
            continue
        evidence = item.get("evidence")
        if not isinstance(evidence, str):
            continue
        if evidence.strip() != host_by_platform.get(os_kind, ""):
            errors.append(
                f"{path.name}: checklist item {key} evidence must match final summary {os_kind} hostname"
            )
    return errors


def _validate_final_summary_sidecar_evidence(
    path: Path,
    items: list[Any],
    final_summary: Path,
) -> list[str]:
    errors: list[str] = []
    expected = final_summary.with_suffix(final_summary.suffix + ".sha256").resolve(strict=False)
    for item in items:
        if not isinstance(item, dict):
            continue
        if str(item.get("key") or "") != "final_summary_hash_sidecar":
            continue
        evidence = item.get("evidence")
        if not isinstance(evidence, str) or not evidence.strip():
            continue
        actual = _resolve_recorded_path(evidence.strip(), path.parent).resolve(strict=False)
        if actual != expected:
            errors.append(
                f"{path.name}: checklist item final_summary_hash_sidecar evidence must point to final summary checksum sidecar"
            )
    return errors


def _validate_source_checklist_evidence(
    approval: dict[str, Any],
    checklist: dict[str, Any],
) -> list[str]:
    errors: list[str] = []
    approval_items_payload = approval.get("items") or []
    if not isinstance(approval_items_payload, list):
        approval_items_payload = []
    approval_items = {
        str(item.get("key") or ""): item
        for item in approval_items_payload
        if isinstance(item, dict)
    }
    for checklist_item in checklist.get("items") or []:
        if not isinstance(checklist_item, dict):
            continue
        key = str(checklist_item.get("key") or "")
        if key in APPROVAL_ITEM_EVIDENCE_FIELDS:
            continue
        expected = str(checklist_item.get("evidence") or "").strip()
        if not expected:
            continue
        actual = str((approval_items.get(key) or {}).get("evidence") or "").strip()
        if actual != expected:
            errors.append(f"approval item {key} evidence must match source checklist evidence")
    return errors


def _validate_approval_final_summary_matches_source_checklist(
    approval: dict[str, Any],
    checklist: dict[str, Any],
    approval_path: Path,
    checklist_path: Path,
) -> list[str]:
    errors: list[str] = []
    approval_final_summary_text = str(approval.get("final_summary") or "").strip()
    if not approval_final_summary_text:
        return ["final_summary is required"]
    approval_final_summary = _resolve_recorded_path(
        approval_final_summary_text,
        approval_path.parent,
    )
    checklist_final_summary_text = str(checklist.get("final_summary") or "").strip()
    if not checklist_final_summary_text:
        return errors
    checklist_final_summary = _resolve_recorded_path(checklist_final_summary_text, checklist_path.parent)
    if approval_final_summary.resolve(strict=False) != checklist_final_summary.resolve(strict=False):
        errors.append("approval final_summary must match source checklist final_summary")
    approval_final_summary_sha = str(approval.get("final_summary_sha256") or "").strip()
    if not approval_final_summary_sha:
        errors.append("approval final_summary_sha256 is required")
    elif not _is_sha256_hex(approval_final_summary_sha):
        errors.append("approval final_summary_sha256 is malformed")
    elif approval_final_summary_sha != str(checklist.get("final_summary_sha256") or ""):
        errors.append("approval final_summary_sha256 must match source checklist final_summary_sha256")
    return errors


def _validate_approval(path: Path) -> tuple[dict[str, Any] | None, dict[str, Any] | None, list[str]]:
    errors = _validate_sidecar(path, "pilot approval")
    approval, error = _load_json(path)
    if error:
        errors.append(error)
        return None, None, errors
    assert approval is not None
    if approval.get("schema") != APPROVAL_SCHEMA:
        errors.append(f"{path.name}: schema is not {APPROVAL_SCHEMA}")
    if approval.get("status") != "customer_pilot_approved":
        errors.append(f"{path.name}: status must be customer_pilot_approved")
    if approval.get("customer_pilot_ready") is not True:
        errors.append(f"{path.name}: customer_pilot_ready must be true")

    approval_details = approval.get("approval")
    if not isinstance(approval_details, dict):
        approval_details = {}
        errors.append(f"{path.name}: approval must be an object")
    approval_field_values: dict[str, str] = {}
    for field in sorted(REQUIRED_APPROVAL_FIELDS):
        value = approval_details.get(field)
        if not isinstance(value, str):
            errors.append(f"{path.name}: approval.{field} must be a string")
            approval_field_values[field] = ""
        elif not value.strip():
            errors.append(f"{path.name}: approval.{field} is required")
            approval_field_values[field] = ""
        elif _is_placeholder_approval_evidence(value):
            errors.append(f"{path.name}: approval.{field} cannot be placeholder approval evidence")
            approval_field_values[field] = value.strip()
        else:
            approval_field_values[field] = value.strip()
    pilot_hostname = approval_field_values.get("pilot_hostname", "")
    if pilot_hostname and not _is_windows_computer_name(pilot_hostname):
        errors.append(
            f"{path.name}: approval.pilot_hostname must be a valid Windows computer name using ASCII letters, numbers, or hyphens"
        )

    approval_items_payload = approval.get("items") or []
    if isinstance(approval_items_payload, list):
        errors.extend(_validate_approval_item_entries(path, approval_items_payload))
        errors.extend(_validate_approval_item_keys(path, approval_items_payload))
        errors.extend(_validate_approval_item_status_types(path, approval_items_payload))
        duplicates = _duplicate_item_keys(approval_items_payload)
        if duplicates:
            errors.append(f"{path.name}: duplicate approval item(s): {', '.join(duplicates)}")
        unknown = _unknown_item_keys(approval_items_payload)
        if unknown:
            errors.append(f"{path.name}: unknown approval item(s): {', '.join(unknown)}")
    else:
        approval_items_payload = []
        errors.append(f"{path.name}: items must be a list")
    approval_items = {
        str(item.get("key") or ""): item
        for item in approval_items_payload
        if isinstance(item, dict)
    }
    errors.extend(_validate_approval_item_evidence_types(path, approval_items))
    items = {key: str(item.get("status") or "") for key, item in approval_items.items()}
    missing = sorted(REQUIRED_ITEM_KEYS - set(items))
    if missing:
        errors.append(f"{path.name}: missing approval item(s): {', '.join(missing)}")
    for key in sorted(REQUIRED_ITEM_KEYS):
        if items.get(key) != "passed":
            errors.append(f"{path.name}: approval item {key} must be passed")
    for item_key, approval_field in sorted(APPROVAL_ITEM_EVIDENCE_FIELDS.items()):
        item = approval_items.get(item_key) or {}
        expected = approval_field_values.get(approval_field, "")
        actual = str(item.get("evidence") or "").strip()
        if expected and actual != expected:
            errors.append(f"{path.name}: approval item {item_key} evidence must match approval.{approval_field}")

    source_checklist_text = str(approval.get("source_checklist") or "").strip()
    if not source_checklist_text:
        checklist = None
        final_summary = None
        errors.append("source_checklist is required")
    else:
        checklist_path = _resolve_recorded_path(source_checklist_text, path.parent)
        checklist, final_summary, checklist_errors = _validate_checklist(checklist_path, approval)
        errors.extend(checklist_errors)
    if checklist is not None:
        errors.extend(
            _validate_approval_final_summary_matches_source_checklist(
                approval,
                checklist,
                path,
                checklist_path,
            )
        )
        errors.extend(_validate_source_checklist_evidence(approval, checklist))
        errors.extend(_validate_pilot_hostname_against_lab_hosts(approval, checklist, final_summary))
    approval_final_summary_text = str(approval.get("final_summary") or "").strip()
    if not approval_final_summary_text:
        final_summary_path = None
        final_summary_direct = None
    else:
        final_summary_path = _resolve_recorded_path(approval_final_summary_text, path.parent)
        final_summary_direct, final_errors = _validate_final_summary(
            final_summary_path,
            str(approval.get("final_summary_sha256") or ""),
        )
        errors.extend(final_errors)
    if final_summary and final_summary_direct:
        approval_final_summary_sha = str(approval.get("final_summary_sha256") or "").strip()
        if (
            final_summary_path is not None
            and _is_sha256_hex(approval_final_summary_sha)
            and _sha256(final_summary_path) != approval_final_summary_sha
        ):
            errors.append("approval final_summary_sha256 mismatch")
    summary_for_build = final_summary or final_summary_direct
    if summary_for_build is not None:
        approval_build_manifest_sha = str(approval.get("build_manifest_sha256") or "").strip()
        if not approval_build_manifest_sha:
            errors.append("approval build_manifest_sha256 is required")
        elif not _is_sha256_hex(approval_build_manifest_sha):
            errors.append("approval build_manifest_sha256 is malformed")
        elif approval_build_manifest_sha != summary_for_build.get("build_manifest_sha256"):
            errors.append("approval build_manifest_sha256 mismatch")
    return approval, final_summary or final_summary_direct, errors


def validate(approval_path: Path) -> tuple[dict[str, Any] | None, dict[str, Any] | None, list[str]]:
    return _validate_approval(approval_path)


def main(argv: list[str]) -> int:
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("--approval", required=True, type=Path, help="legacy-windows-first-iteration-pilot-approval.json")
    args = parser.parse_args(argv)

    approval, _summary, errors = validate(args.approval)
    if errors:
        print("legacy Windows first-iteration pilot readiness failed", file=sys.stderr)
        for error in errors:
            print(f"- {error}", file=sys.stderr)
        return 2

    assert approval is not None
    approval_details = approval.get("approval") or {}
    checklist = _resolve_recorded_path(
        str(approval.get("source_checklist") or ""),
        args.approval.parent,
    )
    final_summary = _resolve_recorded_path(
        str(approval.get("final_summary") or ""),
        args.approval.parent,
    )
    print("legacy Windows first-iteration pilot readiness passed")
    print(f"customer: {approval_details.get('customer')}")
    print(f"pilot hostname: {approval_details.get('pilot_hostname')}")
    print(f"approval sha256: {_sha256(args.approval)}")
    print(f"checklist sha256: {_sha256(checklist)}")
    print(f"final summary sha256: {_sha256(final_summary)}")
    return 0


if __name__ == "__main__":
    raise SystemExit(main(sys.argv[1:]))
