from __future__ import annotations

import datetime
import hashlib
import json
from pathlib import Path

import pandas as pd

ROOT = Path(__file__).resolve().parents[1]
DATA = ROOT / "datasets" / "ai_guardrail_benchmark.csv"
OUT = ROOT / "results" / "row24_ai" / "result.json"
LEGACY = ROOT / "research" / "row24" / "legacy_gate_row24_ai_auc_mismatch.py"
FIG_LOSS = ROOT / "figs" / "learning_efficiency.pdf"
FIG_AI = ROOT / "figs" / "ai_utfanswf_learning.pdf"


def utc_now_z() -> str:
    return datetime.datetime.now(datetime.UTC).isoformat(timespec="seconds").replace("+00:00", "Z")


def sha256(path: Path) -> str | None:
    if not path.exists():
        return None
    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 gate_row24_ai() -> dict:
    if not DATA.exists():
        return {
            "row": 24,
            "gate": "ai_utfanswf_benchmark_record",
            "context": "LIVE",
            "tier": "Diagnostic",
            "blocking": False,
            "timestamp_utc": utc_now_z(),
            "verdict": "PENDING_DATA",
            "status": "PENDING_AI_BENCHMARK_TABLE",
            "notes": "Missing datasets/ai_guardrail_benchmark.csv",
        }

    df = pd.read_csv(DATA)
    required = ["model", "baseline_auc", "utfanswf_auc", "safety_violations"]
    missing = [c for c in required if c not in df.columns]
    if missing:
        return {
            "row": 24,
            "gate": "ai_utfanswf_benchmark_record",
            "context": "LIVE",
            "tier": "Diagnostic",
            "blocking": False,
            "timestamp_utc": utc_now_z(),
            "verdict": "PENDING_DATA",
            "status": "PENDING_AI_BENCHMARK_SCHEMA",
            "notes": f"Benchmark table missing required columns: {missing}",
        }

    for c in ["baseline_auc", "utfanswf_auc", "safety_violations"]:
        df[c] = pd.to_numeric(df[c], errors="coerce")
    complete = bool(df[required].notna().all().all())
    df["classification_auc_gain"] = df["utfanswf_auc"] - df["baseline_auc"]

    metrics = {
        "n_models": int(len(df)),
        "mean_classification_auc_gain": float(df["classification_auc_gain"].mean()),
        "min_classification_auc_gain": float(df["classification_auc_gain"].min()),
        "total_table_safety_violations": int(df["safety_violations"].sum()),
        "all_table_rows_non_decreasing_classification_auc": bool((df["classification_auc_gain"] >= 0).all()),
    }

    checks = {
        "benchmark_schema_complete": complete,
        "benchmark_has_rows": len(df) > 0,
        "classification_auc_values_in_unit_interval": bool(
            ((df["baseline_auc"] >= 0) & (df["baseline_auc"] <= 1)).all()
            and ((df["utfanswf_auc"] >= 0) & (df["utfanswf_auc"] <= 1)).all()
        ),
        "table_reports_zero_safety_violations": metrics["total_table_safety_violations"] == 0,
        "legacy_metric_mismatch_not_overclaimed": True,
        "loss_auc_gate_marked_open": True,
        "privacy_permission_runtime_logs_marked_open": True,
    }

    verdict = "PASS" if all(checks.values()) else "FAIL"
    status = (
        "PASS_AI_BENCHMARK_TABLE_REPRODUCED__LOSS_AUC_AND_SAFETY_RUNTIME_GATES_OPEN"
        if verdict == "PASS"
        else "FAIL_AI_BENCHMARK_TABLE_REPRODUCTION"
    )

    return {
        "row": 24,
        "gate": "ai_utfanswf_benchmark_record",
        "signature": "ROW24_V23_METRIC_SCOPE_HARDENING_v1",
        "context": "LIVE",
        "tier": "Diagnostic",
        "blocking": False,
        "timestamp_utc": utc_now_z(),
        "verdict": verdict,
        "status": status,
        "checks": checks,
        "metrics": metrics,
        "benchmark_table": {
            "path": "datasets/ai_guardrail_benchmark.csv",
            "sha256": sha256(DATA),
            "semantic_type": "classification-like AUC benchmark table as shipped",
        },
        "historical_figures": {
            "learning_efficiency_pdf": {"present": FIG_LOSS.exists(), "sha256": sha256(FIG_LOSS)},
            "ai_utfanswf_learning_pdf": {"present": FIG_AI.exists(), "sha256": sha256(FIG_AI)},
            "source_training_curve_data_shipped": False,
        },
        "claim_boundary": {
            "manuscript_metric": "The manuscript defines AUC as the time integral of validation loss, where lower constrained/baseline ratio is better.",
            "shipped_table_metric": "The CSV fields behave like classification ROC-AUC scores, where higher values are better; this is a different metric.",
            "not_claimed": [
                "The shipped classification-AUC table does not reproduce the manuscript loss-AUC ratio R_AUC.",
                "The table's safety_violations column is not a step-by-step spectral/privacy/permission runtime audit.",
                "The figure PDFs are historical visual artifacts; v23 does not reconstruct training data from plotted curves and call it source data.",
            ],
        },
        "open_boundaries": [
            "Ship the original baseline and constrained validation-loss curves with iteration/time coordinates and freeze kappa; then compute the manuscript loss-AUC ratio directly.",
            "Ship per-step spectral-radius, privacy-accountant, and permission-lattice logs before claiming the full Row 24 safety-rail gate is executable.",
        ],
        "provenance": {
            "legacy_gate": "research/row24/legacy_gate_row24_ai_auc_mismatch.py",
            "legacy_gate_sha256": sha256(LEGACY),
            "specification": "research/row24/ROW24_AI_EXECUTABLE_SCOPE_V23.md",
        },
        "notes": "Diagnostic PASS means the shipped benchmark table is reproduced with its metric semantics corrected; the manuscript loss-AUC and full runtime safety-rail gates remain open.",
    }


def main() -> None:
    OUT.parent.mkdir(parents=True, exist_ok=True)
    res = gate_row24_ai()
    OUT.write_text(json.dumps(res, indent=2, sort_keys=True), encoding="utf-8")
    print(json.dumps({"row": 24, "status": res.get("status"), "verdict": res.get("verdict")}, indent=2))


if __name__ == "__main__":
    main()
