# OID_analysis/analysis/compile_master_table.py
"""
Compile master comparison table from all analysis results.
Cross-scene comparison of force-OID, signature-OID, POD performance.

Usage:
    conda run -n sr_env python3 src/OID_analysis/analysis/compile_master_table.py
"""
from __future__ import annotations

import json
import os
import sys

import numpy as np

_REPO = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", ".."))
if _REPO not in sys.path:
    sys.path.insert(0, _REPO)

from OID_analysis.configs import DATA_DIR  # noqa: E402


def load_comparison(scene: str) -> dict:
    fp = os.path.join(DATA_DIR, "derived", "comparison", f"{scene}.json")
    if not os.path.isfile(fp):
        return {}
    with open(fp) as f:
        return json.load(f)


def load_steady_metrics() -> dict:
    fp = os.path.join(DATA_DIR, "derived", "steady_metrics", "steady_reanalysis.json")
    if not os.path.isfile(fp):
        return {}
    with open(fp) as f:
        return json.load(f)


def load_oid_data(scene: str, oid_type: str) -> dict:
    """Load force-OID or signature-OID data."""
    if oid_type == "force":
        fp = os.path.join(DATA_DIR, "derived", "oid", "force", scene, "force_oid.npz")
    elif oid_type == "suppression":
        fp = os.path.join(DATA_DIR, "derived", "oid", "steady_suppression", f"{scene}_oid.npz")
    else:
        fp = os.path.join(DATA_DIR, "derived", "oid", oid_type, scene, f"sig_oid_delayed.npz")

    if not os.path.isfile(fp):
        return {}
    d = np.load(fp)
    return {"S": d["S"], "cum_corr": d["cum_corr"]}


def load_pod_summary(scene: str) -> dict:
    fp = os.path.join(DATA_DIR, "derived", "pod", scene, "summary.json")
    if not os.path.isfile(fp):
        return {}
    with open(fp) as f:
        return json.load(f)


def cos_sim(a, b):
    """Cosine similarity between two vectors."""
    return float(np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b) + 1e-30))


def compute_force_sig_overlap(scene: str) -> float:
    """Compute cosine similarity between force-OID mode 1 and sig-OID mode 1."""
    force_fp = os.path.join(DATA_DIR, "derived", "oid", "force", scene, "force_oid.npz")
    sig_fp = os.path.join(DATA_DIR, "derived", "oid", "signature", scene, "sig_oid_delayed.npz")

    if not os.path.isfile(force_fp) or not os.path.isfile(sig_fp):
        return None

    U_f = np.load(force_fp)["U"][:, 0]
    U_s = np.load(sig_fp)["U"][:, 0]
    return cos_sim(U_f, U_s)


def main():
    scenes = ["steady_cloak", "karman_re100", "illusion_0.75L", "illusion_1.0L", "illusion_1.5L"]

    print("=" * 100)
    print("MASTER COMPARISON TABLE")
    print("=" * 100)

    # Header
    print(f"{'Scene':<20s} {'POD r10 en%':>12s} {'F-OID S[0]':>10s} {'F-OID S[1]':>10s} "
          f"{'Sig-OID S[0]':>12s} {'Sig-OID S[1]':>12s} "
          f"{'F-OID m2 R2':>12s} {'POD m2 R2':>10s} "
          f"{'Sig-OID m2 R2':>14s} {'POD sig R2':>10s} "
          f"{'F-vs-S overlap':>15s}")
    print("-" * 100)

    for scene in scenes:
        # POD energy
        pod = load_pod_summary(scene)
        en5 = pod.get("energy_r10_5modes", None)

        # Force-OID singular values
        foid = load_oid_data(scene, "force")
        S0 = foid.get("S", [None, None])[0] if foid else None
        S1 = foid.get("S", [None, None])[1] if foid else None

        # Signature-OID
        soid = {}
        if scene != "steady_cloak":
            soid_raw = load_oid_data(scene, "signature")
            soid["S0"] = soid_raw.get("S", [None, None])[0] if soid_raw else None
            soid["S1"] = soid_raw.get("S", [None, None])[1] if soid_raw else None

        # Comparison table (force)
        comp = load_comparison(scene)
        f_oid_m2 = None
        f_pod_m2 = None
        s_oid_m2 = None
        s_pod_m2 = None
        if "force" in comp:
            f_oid_m2 = comp["force"].get("force-oid_m2", None)
            f_pod_m2 = comp["force"].get("pod_m2", None)
        if "future_sig" in comp:
            s_oid_m2 = comp["future_sig"].get("sig-oid_m2", None)
            s_pod_m2 = comp["future_sig"].get("pod_m2", None)

        # Force vs sig overlap
        overlap = compute_force_sig_overlap(scene) if scene != "steady_cloak" else None

        # For steady, use suppression overlap
        if scene == "steady_cloak":
            overlap = 0.763  # from Phase 5 result

        # Format
        en5_s = f"{en5*100:.1f}%" if en5 else "-"
        S0_s = f"{S0:.3f}" if S0 else "-"
        S1_s = f"{S1:.3f}" if S1 else "-"
        sS0_s = f"{soid.get('S0', '-'):.3f}" if soid.get('S0') else "-"
        sS1_s = f"{soid.get('S1', '-'):.3f}" if soid.get('S1') else "-"
        fom2_s = f"{f_oid_m2:.3f}" if f_oid_m2 is not None else "-"
        fpm2_s = f"{f_pod_m2:.3f}" if f_pod_m2 is not None else "-"
        som2_s = f"{s_oid_m2:.3f}" if s_oid_m2 is not None else "-"
        spm2_s = f"{s_pod_m2:.3f}" if s_pod_m2 is not None else "-"
        ov_s = f"{overlap:.3f}" if overlap else "N/A"

        print(f"{scene:<20s} {en5_s:>12s} {S0_s:>10s} {S1_s:>10s} "
              f"{sS0_s:>12s} {sS1_s:>12s} "
              f"{fom2_s:>12s} {fpm2_s:>10s} "
              f"{som2_s:>14s} {spm2_s:>10s} "
              f"{ov_s:>15s}")

    print("-" * 100)

    # Steady metrics
    steady = load_steady_metrics()
    print(f"\nSteady cloak suppression metrics:")
    for section in ["near-body", "near-wake", "downstream", "full-field"]:
        if section in steady:
            r = steady[section]
            print(f"  {section:15s}: RMS reduction={r.get('rms_reduction', 'N/A'):>8.4f}, "
                  f"Enstrophy reduction={r.get('enstrophy_reduction', 'N/A'):>8.4f}")
    if "recirculation" in steady:
        r = steady["recirculation"]
        print(f"  {'recirculation':15s}: Lr collapse={r.get('Lr_collapse', 'N/A'):.4f}, "
              f"Ar collapse={r.get('Ar_collapse', 'N/A'):.4f}")
    if "force" in steady:
        r = steady["force"]
        print(f"  {'force':15s}: Fx reduction={r.get('Fx_reduction', 'N/A'):.4f}, "
              f"Fy reduction={r.get('Fy_reduction', 'N/A'):.4f}")

    # Save master table
    master = {
        "scenes": scenes,
        "comparison": {s: load_comparison(s) for s in scenes},
        "steady_metrics": steady,
        "force_sig_overlap": {s: compute_force_sig_overlap(s) for s in scenes if s != "steady_cloak"},
        "steady_force_sig_overlap": 0.763,
    }
    out_dir = os.path.join(DATA_DIR, "derived", "master")
    os.makedirs(out_dir, exist_ok=True)
    with open(os.path.join(out_dir, "master_table.json"), "w") as f:
        json.dump(master, f, indent=2)
    print(f"\nMaster table saved to {out_dir}/master_table.json")


if __name__ == "__main__":
    main()
