"""max_depth スイープの比較パネル生成.

scripts/sweep_max_depth.py の出力から以下を生成:
    - 1×5 輝度マップパネル (shared vmin/vmax)
    - 収束カーブ (max_depth vs CoV / 勾配 / C/P / 動径 min/max)
    - 数値表

実行方法:
    uv run python scripts/build_max_depth_panel.py

前提条件:
    - output/max_depth_sweep/summary.csv + d{N}/luminance.npy が揃っていること

出力:
    - output/_slide_panels/max_depth_sweep.png         (1×5 輝度マップ)
    - output/_slide_panels/max_depth_convergence.png   (収束カーブ)
"""

from __future__ import annotations

import csv
import sys
from pathlib import Path

import matplotlib
import numpy as np

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

from sm_tias_lightsim.evaluation.roi_presets import SIM_ROI, extract_roi_xywh

ROOT = Path(__file__).resolve().parents[1]
SWEEP_BASE = ROOT / "output" / "max_depth_sweep"
SUMMARY_CSV = SWEEP_BASE / "summary.csv"
OUT_LUM_PANEL = ROOT / "output" / "_slide_panels" / "max_depth_sweep.png"
OUT_CONV_PANEL = ROOT / "output" / "_slide_panels" / "max_depth_convergence.png"

# 実機 TARGET (linear + LSC，eval_baseline_dng_target.yaml と整合)
TARGET = {"cov": 0.0695, "gradient": 8.35, "cp": 1.091, "rmm": 0.860}


def _setup_japanese_font() -> None:
    for p in ("C:/Windows/Fonts/meiryo.ttc", "C:/Windows/Fonts/YuGothM.ttc"):
        if Path(p).exists():
            fm.fontManager.addfont(p)
            plt.rcParams["font.family"] = fm.FontProperties(fname=p).get_name()
            return


def main() -> int:
    _setup_japanese_font()

    if not SUMMARY_CSV.exists():
        print(f"エラー: {SUMMARY_CSV} が見つかりません", file=sys.stderr)
        return 1

    with SUMMARY_CSV.open(encoding="utf-8", newline="") as f:
        rows = list(csv.DictReader(f))
    if not rows:
        print("エラー: summary.csv が空", file=sys.stderr)
        return 1

    depths = [int(r["max_depth"]) for r in rows]
    covs = [float(r["cov"]) for r in rows]
    grads = [float(r["gradient_magnitude"]) for r in rows]
    cps = [float(r["center_periphery_ratio"]) for r in rows]
    rmms = [float(r["radial_min_max_ratio"]) for r in rows]
    means = [float(r["mean"]) for r in rows]

    # 各 npy 読み込み
    lums = []
    for r in rows:
        npy = SWEEP_BASE / r["job"] / "luminance.npy"
        if not npy.exists():
            print(f"警告: {npy} 見つからずスキップ", file=sys.stderr)
            lums.append(None)
            continue
        arr = extract_roi_xywh(np.load(npy), SIM_ROI)
        lums.append(arr.mean(axis=-1) if arr.ndim == 3 else arr)

    # 共有 vmin/vmax
    valid = [x for x in lums if x is not None]
    stacked = np.stack(valid)
    vmin = float(np.percentile(stacked, 1))
    vmax = float(np.percentile(stacked, 99))

    # ============ 1×5 輝度マップパネル ============
    n = len(rows)
    fig, axes = plt.subplots(1, n, figsize=(4.5 * n, 5.5))
    if n == 1:
        axes = [axes]
    for ax, d, lum, cov, grad in zip(axes, depths, lums, covs, grads, strict=False):
        if lum is None:
            ax.set_title(f"d={d}  (missing)")
            ax.set_xticks([])
            ax.set_yticks([])
            continue
        im = ax.imshow(lum, cmap="hot", vmin=vmin, vmax=vmax)
        ax.set_title(f"max_depth = {d}\nCoV={cov:.4f}  勾配={grad:.2f}%", fontsize=11)
        ax.set_xticks([])
        ax.set_yticks([])
        plt.colorbar(im, ax=ax, fraction=0.046, pad=0.04)

    fig.suptitle(
        "max_depth スイープ — 輝度マップ (shared vmin/vmax)", fontsize=14, fontweight="bold"
    )
    plt.tight_layout()
    OUT_LUM_PANEL.parent.mkdir(parents=True, exist_ok=True)
    plt.savefig(OUT_LUM_PANEL, dpi=110, bbox_inches="tight")
    print(f"輝度マップパネル保存: {OUT_LUM_PANEL}")

    # ============ 収束カーブ ============
    fig, axes = plt.subplots(2, 2, figsize=(13, 9))
    metrics = [
        ("CoV", covs, TARGET["cov"], "CoV (低いほど均一)"),
        ("勾配 [%]", grads, TARGET["gradient"], "勾配 [%] (低いほど均一)"),
        ("C/P 比", cps, TARGET["cp"], "C/P 比 (1.0 が理想)"),
        ("動径 min/max", rmms, TARGET["rmm"], "動径 min/max (1.0 が理想)"),
    ]
    for ax, (label, vals, target, ylabel) in zip(axes.flat, metrics, strict=False):
        ax.plot(depths, vals, marker="o", linewidth=2, markersize=10, color="C0", label="シミュ")
        ax.axhline(target, color="red", linestyle="--", linewidth=1.5,
                   label=f"実機 TARGET ({target})")
        for d, v in zip(depths, vals, strict=False):
            ax.annotate(f"{v:.4f}", (d, v), textcoords="offset points",
                        xytext=(0, 10), ha="center", fontsize=9)
        ax.set_xlabel("max_depth")
        ax.set_ylabel(ylabel)
        ax.set_title(label)
        ax.grid(alpha=0.3)
        ax.legend(loc="best", fontsize=9)

    fig.suptitle(
        "max_depth スイープ — 形状指標の収束 (赤破線=実機 TARGET)",
        fontsize=14, fontweight="bold",
    )
    plt.tight_layout()
    plt.savefig(OUT_CONV_PANEL, dpi=110, bbox_inches="tight")
    print(f"収束カーブ保存: {OUT_CONV_PANEL}")

    # ============ コンソールサマリ ============
    print()
    print("=== サマリ ===")
    print(f"  {'max_depth':<10}{'mean':<10}{'CoV':<10}{'勾配%':<10}{'C/P':<10}{'r min/max':<10}")
    for d, mean, cov, grad, cp, rmm in zip(depths, means, covs, grads, cps, rmms, strict=False):
        print(f"  {d:<10}{mean:<10.2f}{cov:<10.4f}{grad:<10.2f}{cp:<10.4f}{rmm:<10.4f}")
    print(f"  実機 TARGET:  -         {TARGET['cov']:<10}{TARGET['gradient']:<10}"
          f"{TARGET['cp']:<10}{TARGET['rmm']:<10}")
    return 0


if __name__ == "__main__":
    sys.exit(main())
