#!/usr/bin/env python3
"""veraPDF PDF/UA-1 compliance gate (file-remediation Stage 3 — hard gate).

Runs the vendored veraPDF CLI against a PDF and returns a structured result.
Never claims "fully compliant/conformant" — machine checks only; the Matterhorn
human-checkpoint count (47, constant for PDF/UA-1) is always reported alongside.

Usage: python verapdf_gate.py FILE [--json]
Exit: 0 compliant, 1 not compliant, 2 error (vendor missing / verapdf failure).
"""

from __future__ import annotations

import argparse
import json
import subprocess
import sys
from pathlib import Path

SCRIPTS_DIR = Path(__file__).resolve().parent
if str(SCRIPTS_DIR) not in sys.path:
    sys.path.insert(0, str(SCRIPTS_DIR))

import setup_remediation

# Matterhorn PDF/UA-1: 136 failure conditions total, ~87 machine-checkable,
# ~47 require human judgment (color contrast, alt-text quality, reading order
# correctness, link purpose). Constant for this profile — see plan §1, §7.
MATTERHORN_HUMAN_CHECKPOINTS = 47

TIMEOUT_S = 120


def run_verapdf(pdf_path) -> dict:
    """Run veraPDF --flavour ua1 against pdf_path. Raises RuntimeError if the
    vendored java/verapdf are not installed, or on subprocess failure."""
    java = setup_remediation.get_java()
    verapdf = setup_remediation.get_verapdf()
    if not java or not verapdf:
        raise RuntimeError(
            "veraPDF vendor tools not installed — run "
            "`python scripts/setup_remediation.py --install` first"
        )
    import os
    env = dict(os.environ)
    env["JAVA_HOME"] = str(java.parent.parent)  # .../Contents/Home/bin/java -> .../Contents/Home
    env["PATH"] = f"{java.parent}{os.pathsep}{env.get('PATH', '')}"

    try:
        proc = subprocess.run(
            [str(verapdf), "--flavour", "ua1", "--format", "json", str(pdf_path)],
            capture_output=True, text=True, timeout=TIMEOUT_S, env=env,
        )
    except subprocess.TimeoutExpired as exc:
        raise RuntimeError(f"veraPDF timed out after {TIMEOUT_S}s") from exc

    try:
        data = json.loads(proc.stdout)
    except json.JSONDecodeError as exc:
        raise RuntimeError(
            f"veraPDF produced no parseable JSON (rc={proc.returncode}): "
            f"{proc.stderr[:500]}"
        ) from exc

    jobs = data.get("report", {}).get("jobs") or []
    validation = (jobs[0].get("validationResult") or [{}])[0] if jobs else {}
    details = validation.get("details", {})
    failed_summaries = [
        {
            "clause": rs.get("clause"),
            "description": rs.get("description"),
            "failedChecks": rs.get("failedChecks"),
        }
        for rs in (details.get("ruleSummaries") or [])
        if rs.get("failedChecks")
    ]

    return {
        "compliant": validation.get("compliant"),
        "passed_rules": details.get("passedRules"),
        "failed_rules": details.get("failedRules"),
        "failed_summaries": failed_summaries,
        "passed_checks": details.get("passedChecks"),
        "matterhorn_human_checkpoints": MATTERHORN_HUMAN_CHECKPOINTS,
        "profile": f"PDF/UA-1 (veraPDF {setup_remediation.VERAPDF_VERSION})",
    }


def main():
    parser = argparse.ArgumentParser(description="veraPDF PDF/UA-1 compliance gate")
    parser.add_argument("file")
    parser.add_argument("--json", action="store_true")
    args = parser.parse_args()

    try:
        result = run_verapdf(args.file)
    except RuntimeError as exc:
        if args.json:
            print(json.dumps({"error": str(exc)}), file=sys.stderr)
        else:
            print(f"ERROR: {exc}", file=sys.stderr)
        sys.exit(2)

    if args.json:
        print(json.dumps(result, indent=2))
    else:
        status = "COMPLIANT" if result["compliant"] else "NOT COMPLIANT"
        print(f"{status}: {result['passed_rules']} rules passed, "
              f"{result['failed_rules']} failed "
              f"({result['matterhorn_human_checkpoints']} human checkpoints not machine-checked)")
        for s in result["failed_summaries"]:
            print(f"  FAIL {s['clause']}: {s['description']}")
    sys.exit(0 if result["compliant"] else 1)


if __name__ == "__main__":
    main()
