#!/usr/bin/env python3
import csv
import json
import math
from pathlib import Path

import matplotlib

matplotlib.use("Agg")
import matplotlib.pyplot as plt


ROOT = Path(__file__).resolve().parents[1]
DATA = ROOT / "data" / "F1_proxy_substitution_r1_data.csv"
OUT_PNG = ROOT / "figures" / "F1_proxy_substitution_r1.png"
OUT_SVG = ROOT / "figures" / "F1_proxy_substitution_r1.svg"
OUT_VALIDATION = ROOT / "validation" / "F1_proxy_substitution_r1_validation.json"
EXPECTED = ["true_true", "true_est", "est_true", "est_est"]
TITLE = "Using a realization proxy raises the apparent violation rate\nmore than using a threshold proxy"


def validate_rows(rows):
    checked = []
    for row in rows:
        item = dict(row)
        item["n"] = int(item["n"])
        item["violations"] = int(item["violations"])
        item["rate_pct"] = float(item["rate_pct"])
        computed = 100.0 * item["violations"] / item["n"]
        if not math.isclose(computed, item["rate_pct"], abs_tol=0.0051):
            raise ValueError(f"rate mismatch for {item['scenario']}: {computed} vs {item['rate_pct']}")
        checked.append(item)
    if [row["scenario"] for row in checked] != EXPECTED:
        raise ValueError("unexpected scenario order")
    if len({row["n"] for row in checked}) != 1:
        raise ValueError("denominator is not fixed")
    if any(row.get("evidence_class") != "reported_empirical" for row in checked):
        raise ValueError("canonical rows must be reported_empirical")
    return checked


def read_rows(path=DATA):
    with Path(path).open(newline="", encoding="utf-8") as handle:
        return validate_rows(list(csv.DictReader(handle)))


def build_validation(rows):
    raw = {row["scenario"]: 100.0 * row["violations"] / row["n"] for row in rows}
    baseline = raw["true_true"]
    differences = {
        "threshold_proxy": round(raw["true_est"] - baseline, 2),
        "realization_proxy": round(raw["est_true"] - baseline, 2),
        "both_proxies": round(raw["est_est"] - baseline, 2),
    }
    interaction = round(
        differences["both_proxies"]
        - differences["threshold_proxy"]
        - differences["realization_proxy"],
        2,
    )
    return {
        "status": "PASS",
        "evidence_class": "reported_empirical_transcription",
        "n": rows[0]["n"],
        "reported_counts": {row["scenario"]: row["violations"] for row in rows},
        "reported_rates_pct": {row["scenario"]: row["rate_pct"] for row in rows},
        "recomputed_rates_pct": raw,
        "max_rounding_error_percentage_points": max(abs(raw[row["scenario"]] - row["rate_pct"]) for row in rows),
        "percentage_point_differences": differences,
        "nonadditive_interaction_percentage_points": interaction,
        "causal_or_additive_claim": False,
        "common_population": True,
        "individual_transition_counts_available": False,
        "source_version": "retained November 2024 preprint",
        "source_sha256": "a308c23caca817aacedcb099600992a9f49876047654f41abfe21e0e70acfe1f",
        "source_locator": "Table 3 Panel B, printed p.47 / PDF p.48",
        "outputs": [str(OUT_PNG.relative_to(ROOT)), str(OUT_SVG.relative_to(ROOT))],
        "exclusions": [
            "no microdata replication",
            "no individual transition claim",
            "not legal ground truth",
            "not market-wide prevalence",
            "not EOJI performance",
        ],
    }


def make_figure(rows):
    baseline = rows[0]["rate_pct"]
    comparisons = rows[1:]
    labels = ["Threshold proxy only", "Realization proxy only", "Both proxies"]
    y = [2, 1, 0]

    plt.rcParams.update({
        "font.family": "DejaVu Sans",
        "font.size": 10,
        "axes.titlesize": 13,
        "axes.labelsize": 10,
        "svg.hashsalt": "eoji-v07-r1-f1",
    })
    fig, ax = plt.subplots(figsize=(11.8, 5.7), constrained_layout=True)
    for yi, row, label in zip(y, comparisons, labels):
        rate = row["rate_pct"]
        ax.plot([baseline, rate], [yi, yi], color="#66717e", linewidth=2.2, zorder=1)
        ax.scatter([baseline], [yi], facecolors="white", edgecolors="#1b2a41", s=80, linewidth=1.8, zorder=3)
        ax.scatter([rate], [yi], color="#1b2a41", s=80, zorder=3)
        ax.text(baseline, yi + 0.16, f"{baseline:.2f}%", ha="center", va="bottom", fontsize=9.2)
        ax.text(rate + 0.45, yi, f"{rate:.2f}%  (+{rate - baseline:.2f} pp)", ha="left", va="center", fontsize=10)
        ax.text(-0.35, yi, label, ha="right", va="center", fontweight="semibold")

    ax.axvline(baseline, color="#1b2a41", linestyle="--", linewidth=1.0)
    ax.text(baseline, 2.55, "Issuer-reported realization\n+ issuer-reported threshold", ha="center", va="bottom", fontsize=9)
    ax.set_xlim(0, 24.0)
    ax.set_ylim(-0.65, 2.75)
    ax.set_xlabel("Apparent covenant-violation rate (%)")
    ax.set_yticks([])
    ax.set_title(TITLE, loc="left", fontweight="bold")
    ax.text(0, -0.53, "Common reported analysis population: N = 14,623 covenant observations", fontsize=9, color="#3f4854")
    ax.grid(axis="x", color="#d5d9dd", linewidth=0.8)
    ax.set_axisbelow(True)
    for spine in ("top", "right", "left"):
        ax.spines[spine].set_visible(False)
    ax.spines["bottom"].set_color("#7a828a")

    metadata = {"Creator": "EOJI v0.7 R1 correction", "Date": None}
    fig.savefig(OUT_PNG, dpi=220, metadata=metadata)
    fig.savefig(OUT_SVG, metadata=metadata)
    plt.close(fig)


def main():
    rows = read_rows()
    make_figure(rows)
    OUT_VALIDATION.write_text(json.dumps(build_validation(rows), indent=2) + "\n", encoding="utf-8")


if __name__ == "__main__":
    main()
