# OID_analysis/analysis/phase5_steady_oid.py
"""
Phase 5: Steady cloak dedicated suppression-OID / mean-wake OID.

Steady cloak is NOT a periodic future-signature problem. We analyze:
1. Force-OID (from Phase 3)
2. Fluctuation-OID: find correction structures correlated with fluctuation suppression
3. Mean-wake OID: find correction structures correlated with wake restoration

Usage:
    python3 src/OID_analysis/analysis/phase5_steady_oid.py
"""
from __future__ import annotations

import argparse
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
from OID_analysis.utils.analysis import (  # noqa: E402
    compute_force_oid as compute_oid,
    standardize, reconstruct_oid_modes,
)


def run_steady_oid():
    print(f"\n--- Phase 5: Steady Cloak Suppression-OID ---")

    scene_key = "steady_cloak"

    # Load POD coefs
    pod_dir = os.path.join(DATA_DIR, "derived", "pod", scene_key)
    pod_fp = os.path.join(pod_dir, "pod_coefs_r10.npy.npz")
    if not os.path.isfile(pod_fp):
        print(f"  WARNING: POD not found at {pod_fp}")
        return
    pod_npz = np.load(pod_fp, allow_pickle=True)
    coefs = pod_npz["coefs"]

    # Load observables
    obs_dir = os.path.join(DATA_DIR, "derived", "observables", scene_key)

    results = {}
    obs_to_run = {
        "suppression_rms": "rms_uy",      # fluctuation suppression
        "suppression_uxdev": "ux_deviation",  # wake restoration
        "force_total": "force_total",       # force
    }

    for result_key, obs_name in obs_to_run.items():
        fp = os.path.join(obs_dir, f"{obs_name}.npz")
        if not os.path.isfile(fp):
            print(f"  WARNING: {obs_name} not found")
            continue

        data = np.load(fp)
        Y = data["standardized"]

        N = min(coefs.shape[0], Y.shape[0])
        A_std, _, _ = standardize(coefs[:N])
        Y_cut = Y[:N]

        oid = compute_oid(A_std, Y_cut)
        results[result_key] = oid
        print(f"  {result_key}: S[0]={oid['S'][0]:.4f}, cum_corr[:3]={oid['cum_corr'][:3]}")

    # Compare force-OID and suppression-OID mode overlap
    if "force_total" in results and "suppression_rms" in results:
        U_F = results["force_total"]["U"]
        U_S = results["suppression_rms"]["U"]
        # Cosine similarity between first modes
        cos_sim = float(abs(np.dot(U_F[:, 0], U_S[:, 0])))
        print(f"  Force-OID vs Suppression-OID mode 1 overlap: {cos_sim:.4f}")

    # Save
    out_dir = os.path.join(DATA_DIR, "derived", "oid", "steady_suppression")
    os.makedirs(out_dir, exist_ok=True)
    for name, oid in results.items():
        np.savez(os.path.join(out_dir, f"{name}_oid.npz"),
                 z=oid["z"], S=oid["S"], U=oid["U"], cum_corr=oid["cum_corr"])

    print(f"  Saved to {out_dir}")


def main():
    ap = argparse.ArgumentParser()
    ap.parse_args()
    run_steady_oid()
    print("Phase 5 complete.")


if __name__ == "__main__":
    main()
