#!/usr/bin/env python3
"""Draw the published C-07 result matrix. Requires matplotlib; no network calls.

Run in an empty output directory: python path/to/figure-source.py
Reads results.csv beside this script. Writes results-overview.svg and .png.
"""
import csv
import hashlib
from pathlib import Path

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


def main():
    source = Path(__file__).with_name("results.csv")
    rows = list(csv.DictReader(source.read_text(encoding="utf-8").splitlines()))
    if [r["case"] for r in rows] != [f"S{i}" for i in range(1, 7)]:
        raise ValueError("Expected six ordered C-07 cases")
    for name in ("results-overview.svg", "results-overview.png"):
        if Path(name).exists():
            raise FileExistsError("Use an empty output directory")
    plt.rcParams.update({"font.family": "DejaVu Sans", "svg.hashsalt": "C07-20260903"})
    fig = plt.figure(figsize=(14, 9), facecolor="#f7f5ef")
    ax = fig.add_axes([0, 0, 1, 1])
    ax.set_axis_off()
    ink, muted = "#17272d", "#465860"
    ax.text(.045, .947, "RESTORE LAB  /  SIX DESIGNED CASES", color=muted, fontsize=11, weight="bold")
    ax.text(.045, .884, "A successful command is only one check", color=ink, fontsize=26, weight="bold")
    ax.text(.045, .843, "12 synthetic files · 2,330 baseline bytes · Windows · restic 0.19.1 · run: 2026-09-03",
            color=muted, fontsize=11)
    ax.text(.36, .77, "COMMAND EXIT CODES", color=muted, fontsize=10, weight="bold")
    ax.text(.646, .77, "RECOVERY CHECKS", color=muted, fontsize=10, weight="bold")
    labels = ["S1   Normal", "S2   Wrong test password", "S3   One ciphertext byte changed",
              "S4   Required file excluded", "S5   Older snapshot requested", "S6   Invalid JSON before backup"]
    cells = []
    for label, row in zip(labels, rows):
        expected = row["expected_count"]
        attempted = row["parser_attempted_count"]
        cells.append([label, row["check_exit"], row["read_data_exit"], row["restore_exit"],
                      f'{row["restored_count"]}/{expected}',
                      f'{row["matching_hash_count"]}/{expected}',
                      "Not tested" if attempted == "0" else f'{row["parser_pass_count"]}/{attempted}'])
    table = ax.table(cellText=cells, colLabels=["Condition", "check", "check\n--read-data", "restore",
                     "Files\nrestored", "Required\nhashes match", "Format reads\npass/attempted"],
                     cellLoc="center", colWidths=[.335,.075,.105,.085,.12,.135,.145],
                     bbox=[.04,.335,.92,.415])
    table.auto_set_font_size(False)
    table.set_fontsize(10.7)
    for (row, col), cell in table.get_celld().items():
        cell.set_edgecolor("#d6dddd")
        cell.set_linewidth(.8)
        cell.set_text_props(color=ink)
        if row == 0:
            cell.set_facecolor("#dfe7e5")
            cell.set_text_props(weight="bold", fontsize=10)
        else:
            cell.set_facecolor("#fffefa" if row % 2 else "#edf1ed")
            if col == 0: cell.set_text_props(ha="left")
            if col >= 4 and cells[row-1][col] not in ("12/12", "11/11"):
                cell.set_facecolor("#f5dcc2")
                cell.set_text_props(weight="bold")
        cell.PAD = .045
    notes = [
        "0 = command reported success. This does not establish that the recovery goal was met.",
        "Files and hashes: denominator = 12 intended files. Format reads: denominator = files actually tested.",
        "S3/S4: 11/11 format reads does not mean all 12 files were recovered. S2: no format checks ran.",
        "S5: 11/12 matches the required current version; 12/12 matches the older snapshot actually requested.",
        "S6: invalid JSON was already present before backup. Restoration preserved its bytes correctly.",
    ]
    for i, note in enumerate(notes):
        ax.text(.045, .291 - i*.036, note, color=ink, fontsize=10)
    ax.text(.045, .085, "One bounded local experiment; not failure rates, a product ranking, or a real-backup safety test.",
            color=muted, fontsize=10, style="italic")
    ax.text(.045, .047, "Cora Aegis · cypherpunkguide.com/en/sovereignty/encrypted-backup-restore-test/ · source: results.csv",
            color=muted, fontsize=8.7)
    fig.savefig("results-overview.svg", metadata={"Date": None, "Creator": "Cora Aegis",
                    "Title": "C-07: six restoration cases and separate recovery checks",
                    "Description": "Derived from published results.csv; " + " ".join(notes)})
    fig.savefig("results-overview.png", dpi=140, metadata={"Software": "Cora Aegis / matplotlib"})
    plt.close(fig)
    print("source_csv_sha256=" + hashlib.sha256(source.read_bytes()).hexdigest())


if __name__ == "__main__":
    main()
