"""
repro_demo.py - Reproducibility demonstration for Chapter 22 Lab (Reproducibility Lab).

This script demonstrates the Sandve et al. (2013) reproducibility rules:
  - Rule 1: track how every result was produced (this script IS the provenance)
  - Rule 4: version-control all scripts
  - Rule 6: for analyses with randomness, record the seed
  - Rule 7: always store raw data behind plots
  - Rule 9: connect textual statements to underlying results

Dataset: SYNTHETIC ONLY - no real victim data, no real network captures.
The "detection rate" values are randomly generated from a fixed seed; they
represent a hypothetical binary classifier comparison (detector A vs detector B)
on a synthetic labelled dataset. These numbers have no real-world meaning.

SAFETY: This script is a teaching demo. It does not scan, exploit, or interact
with any real system. Run only in the provided container or your own environment.
"""

import hashlib
import os
import pathlib

import matplotlib
matplotlib.use("Agg")  # Non-interactive backend - no display required

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

# ── Reproducibility: fix the seed explicitly (Sandve Rule 6) ─────────────────
SEED = 42
rng = np.random.default_rng(SEED)

OUTPUT_DIR = pathlib.Path("outputs")
OUTPUT_DIR.mkdir(exist_ok=True)

# ── Generate synthetic comparison data ───────────────────────────────────────
# Simulates 20 evaluation runs of two hypothetical detectors on a synthetic dataset.
# Detector A: random-forest baseline. Detector B: proposed model.
n_runs = 20
detector_a_fpr = rng.uniform(0.05, 0.20, n_runs).round(4)
detector_b_fpr = rng.uniform(0.02, 0.12, n_runs).round(4)
detector_a_tpr = rng.uniform(0.70, 0.88, n_runs).round(4)
detector_b_tpr = rng.uniform(0.78, 0.95, n_runs).round(4)

df = pd.DataFrame({
    "run": range(1, n_runs + 1),
    "detector_a_fpr": detector_a_fpr,
    "detector_a_tpr": detector_a_tpr,
    "detector_b_fpr": detector_b_fpr,
    "detector_b_tpr": detector_b_tpr,
})

# ── Save raw data behind every figure (Sandve Rule 7) ────────────────────────
csv_path = OUTPUT_DIR / "synthetic_comparison.csv"
df.to_csv(csv_path, index=False)
print(f"[repro_demo] Saved raw data: {csv_path}")

# ── Plot ROC-style summary ─────────────────────────────────────────────────────
fig, ax = plt.subplots(figsize=(7, 5))
ax.scatter(detector_a_fpr, detector_a_tpr,
           label="Detector A (baseline)", marker="o", color="steelblue", alpha=0.7)
ax.scatter(detector_b_fpr, detector_b_tpr,
           label="Detector B (proposed)", marker="^", color="darkorange", alpha=0.7)
ax.set_xlabel("False Positive Rate")
ax.set_ylabel("True Positive Rate")
ax.set_title(
    "Synthetic detector comparison - SEED=42\n"
    "(Teaching demo: all values are randomly generated)"
)
ax.legend()
ax.set_xlim(-0.01, 0.25)
ax.set_ylim(0.60, 1.01)
fig.tight_layout()

png_path = OUTPUT_DIR / "synthetic_comparison.png"
fig.savefig(png_path, dpi=100)
plt.close(fig)
print(f"[repro_demo] Saved figure: {png_path}")

# ── Print hashes so students can confirm exact reproducibility ────────────────
for path in [csv_path, png_path]:
    digest = hashlib.sha256(path.read_bytes()).hexdigest()
    print(f"[repro_demo] SHA-256 {path.name}: {digest}")

print("\n[repro_demo] Run complete.")
print("  If you re-run this script, the SHA-256 hashes should be identical.")
print("  A different hash means the environment or seed changed (Sandve Rule 6).")
print(f"  SEED used: {SEED}")
print("  Data source: SYNTHETIC (no real network data).")
