#!/usr/bin/env python3
"""Validate deployment evidence fixtures without network or infrastructure access."""
from __future__ import annotations

import json
import re
import sys
from collections import Counter
from datetime import datetime
from pathlib import Path

ROOT = Path(__file__).resolve().parent
CASE_ID = re.compile(r"^DE-[A-Z0-9]+-[0-9]{3}$")
STATUSES = {"PASS", "FAIL", "BLOCKED"}
GATES = {"dns", "tls", "origin", "cors", "csrf", "runtime", "database", "private-s3", "stripe-tax", "platform-package", "health", "readiness", "rollback", "sbom", "provenance", "vulnerability"}


def fail(message: str) -> None:
    raise ValueError(message)


def load_json(path: Path):
    with path.open(encoding="utf-8") as stream:
        return json.load(stream)


def main() -> int:
    # Import is intentionally optional so plain JSON syntax/semantic checks still run.
    try:
        import jsonschema
    except ImportError:
        jsonschema = None

    suite = load_json(ROOT / "suite.json")
    suite_schema = load_json(ROOT / "suite.schema.json")
    case_schema = load_json(ROOT / "case.schema.json")
    cases = []
    with (ROOT / suite["cases_file"]).open(encoding="utf-8") as stream:
        for line_no, line in enumerate(stream, 1):
            try:
                cases.append(json.loads(line))
            except json.JSONDecodeError as exc:
                fail(f"cases.jsonl:{line_no}: invalid JSON: {exc.msg}")

    if jsonschema:
        jsonschema.Draft202012Validator(suite_schema, format_checker=jsonschema.FormatChecker()).validate(suite)
        validator = jsonschema.Draft202012Validator(case_schema)
        for line_no, case in enumerate(cases, 1):
            errors = sorted(validator.iter_errors(case), key=lambda e: list(e.path))
            if errors:
                fail(f"cases.jsonl:{line_no}: schema error: {errors[0].message}")

    if suite.get("case_count") != len(cases):
        fail("suite case_count does not match cases.jsonl")
    ids = [case.get("case_id") for case in cases]
    if any(not isinstance(case_id, str) or not CASE_ID.fullmatch(case_id) for case_id in ids):
        fail("case_id is malformed")
    if len(ids) != len(set(ids)):
        fail("case_id values must be unique")
    evidence_ids = [case["input"].get("evidence_id") for case in cases]
    if len(evidence_ids) != len(set(evidence_ids)):
        fail("evidence_id values must be unique")

    coverage = Counter()
    for case in cases:
        gate = case.get("gate")
        evidence = case.get("input", {})
        expected = case.get("expected", {})
        if gate not in GATES or evidence.get("kind") != gate:
            fail(f"{case.get('case_id')}: gate/kind mismatch")
        outcome = expected.get("outcome")
        if outcome not in STATUSES or evidence.get("status") not in STATUSES:
            fail(f"{case['case_id']}: invalid status")
        if outcome == "PASS" and expected.get("error") is not None:
            fail(f"{case['case_id']}: PASS must have null error")
        if outcome != "PASS" and not expected.get("error"):
            fail(f"{case['case_id']}: non-PASS requires an error")
        if evidence.get("redacted") is not True:
            fail(f"{case['case_id']}: evidence must be redacted")
        for secret_name in evidence.get("secret_names", []):
            if not re.fullmatch(r"[A-Z][A-Z0-9_]*", secret_name):
                fail(f"{case['case_id']}: invalid secret name")
        for field in ("observed_at", "expires_at"):
            value = evidence.get(field)
            if value and value != "not-a-timestamp":
                datetime.fromisoformat(value.replace("Z", "+00:00"))
        coverage[(gate, outcome)] += 1

    missing = sorted(gate for gate in GATES if not any(key[0] == gate for key in coverage))
    if missing:
        fail(f"missing gate coverage: {', '.join(missing)}")
    if not any(c["expected"]["error"] == "EVIDENCE_MALFORMED" for c in cases):
        fail("missing malformed evidence case")
    print(f"validated {len(cases)} cases across {len(GATES)} gates")
    print("outcomes " + " ".join(f"{status}={sum(v for (g, s), v in coverage.items() if s == status)}" for status in sorted(STATUSES)))
    print(f"jsonschema={'enabled' if jsonschema else 'unavailable (semantic checks only)'}")
    return 0


if __name__ == "__main__":
    try:
        raise SystemExit(main())
    except (KeyError, TypeError, ValueError) as exc:
        print(f"validation failed: {exc}", file=sys.stderr)
        raise SystemExit(1)
