#!/usr/bin/env python3
"""
Rebuild the folded CLK+ eye diagram for the v2 report.

The original plot_eye() in make_flicker_report.py looks for an LP-11 → HS
transition (CLK+ > 0.5 V then falling). In session 20260515_135656 the
captures landed entirely in HS state (CLK+ stays in ~0.07–0.36 V), so the
edge detector returned None for every segment and the plot rendered with
zero overlays.

This script auto-detects the common mode per segment and folds around
every crossing of common mode — which is what the eye really wants.
"""

from __future__ import annotations

from pathlib import Path
import numpy as np
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt

ARRIVE_PURPLE      = "#5f016f"
ARRIVE_PURPLE_DARK = "#3e0049"

SESSION = Path("data/flicker_bursts/20260515_135656")
BURST = 15
N_SEGS = 20
UI_NS = 2.315
OUT = Path("flicker_investigation_report_v2_plots/mipi_typical_eye.png")


def fold_segment(t_ns: np.ndarray, v_mv: np.ndarray, ui_ns: float,
                 ax: plt.Axes) -> int:
    """Overlay every common-mode crossing in this segment as a ±1 UI slice."""
    cm = float(np.median(v_mv))
    above = (v_mv > cm).astype(int)
    edges = np.where(np.diff(above) != 0)[0]
    n = 0
    for e in edges:
        t_cross = t_ns[e]
        mask = (t_ns >= t_cross - ui_ns) & (t_ns <= t_ns[e] + ui_ns)
        if mask.sum() < 3:
            continue
        ax.plot(t_ns[mask] - t_cross, v_mv[mask] - cm,
                color=ARRIVE_PURPLE, linewidth=0.4, alpha=0.18)
        n += 1
    return n


def main() -> None:
    clk_files = sorted(SESSION.glob(f"burst_{BURST:04d}_*_mipi_seg*_clk.csv"))
    if not clk_files:
        raise SystemExit(f"no CLK files for burst {BURST} in {SESSION}")

    fig, ax = plt.subplots(figsize=(8.5, 3.0))
    total_segs = 0
    total_xings = 0
    for f in clk_files[:N_SEGS]:
        arr = np.genfromtxt(f, delimiter=",")
        t_ns = arr[:, 0] * 1e9
        v_mv = arr[:, 1] * 1000
        n = fold_segment(t_ns, v_mv, UI_NS, ax)
        if n:
            total_segs += 1
            total_xings += n

    ax.axhline(0, color="grey", linewidth=0.4, alpha=0.5)
    ax.axvline(-UI_NS / 2, color="grey", linestyle=":", linewidth=0.4, alpha=0.5)
    ax.axvline(+UI_NS / 2, color="grey", linestyle=":", linewidth=0.4, alpha=0.5)
    ax.set_xlabel(f"time (ns, folded on UI = {UI_NS} ns)")
    ax.set_ylabel("CLK+ − common-mode (mV)")
    ax.set_xlim(-UI_NS, UI_NS)
    ax.set_title(
        f"CLK+ folded eye ({total_segs} segments × ~{total_xings // max(total_segs,1)} "
        f"crossings overlaid on a 2-UI window, burst {BURST})",
        color=ARRIVE_PURPLE, fontsize=11)
    ax.grid(True, alpha=0.25)
    ax.text(0.01, 0.95,
            f"{total_segs} segments × ~{total_xings // max(total_segs,1)} cycles overlaid",
            transform=ax.transAxes, fontsize=9, color=ARRIVE_PURPLE_DARK,
            bbox=dict(facecolor="white", edgecolor="none", alpha=0.85), va="top")

    OUT.parent.mkdir(parents=True, exist_ok=True)
    fig.tight_layout()
    fig.savefig(OUT, dpi=140)
    print(f"wrote {OUT}  ({total_segs} segments, {total_xings} crossings)")


if __name__ == "__main__":
    main()
