"""
11 — Pearson correlation between POD coefficients and (raw inputs,
     derived inputs, output metrics).

Fits PCA on the first TRAIN_SIZE samples, projects all 2000 onto the
basis, computes Pearson R between each PC coefficient and a curated
set of raw / derived / output quantities, then renders a single table-
style heatmap.
"""

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec
from matplotlib.transforms import blended_transform_factory
from sklearn.decomposition import PCA
from scipy import stats

from _utils import (
    load_data, compute_rth, CHIP_AREA, PARAM_IDX,
    TRAIN_SIZE, N_MODES, PLOTS_DIR,
)

FS = 20

LATEX = {
    # Raw
    "Q1": r"$Q_1$", "Q2": r"$Q_2$",
    "m1": r"$\dot{m}_1$", "m2": r"$\dot{m}_2$",
    "T_in1": r"$T_{\mathrm{in},1}$", "T_in2": r"$T_{\mathrm{in},2}$",
    # Derived
    "Q_total": r"$Q_1 + Q_2$",
    "m_total": r"$\dot{m}_1 + \dot{m}_2$",
    "T_in_avg": r"$\bar{T}_{\mathrm{in}}$",
    "Q1 - Q2": r"$Q_1 - Q_2$",
    "m1 - m2": r"$\dot{m}_1 - \dot{m}_2$",
    "T_in1 - T_in2": r"$T_{\mathrm{in},1} - T_{\mathrm{in},2}$",
    "Q1 / m1": r"$Q_1 / \dot{m}_1$",
    "Q2 / m2": r"$Q_2 / \dot{m}_2$",
    "Q1/m1 - Q2/m2": r"$Q_1/\dot{m}_1 - Q_2/\dot{m}_2$",
    # Outputs
    "Tmax_chip1": r"$T_{\max,\mathrm{chip1}}$",
    "Tmax_chip2": r"$T_{\max,\mathrm{chip2}}$",
    "Rth1": r"$R_{\mathrm{th},1}$",
    "Rth2": r"$R_{\mathrm{th},2}$",
}

DESC = {
    "Q1": "Chip 1 heat load",
    "Q2": "Chip 2 heat load",
    "m1": "Inlet 1 mass flow rate",
    "m2": "Inlet 2 mass flow rate",
    "T_in1": "Inlet 1 temperature",
    "T_in2": "Inlet 2 temperature",
    "Q_total": "Total heat load",
    "m_total": "Total mass flow rate",
    "T_in_avg": "Mean inlet temperature",
    "Q1 - Q2": "Heat load difference",
    "m1 - m2": "Flow rate difference",
    "T_in1 - T_in2": "Inlet temp. difference",
    "Q1 / m1": "Side 1 thermal load",
    "Q2 / m2": "Side 2 thermal load",
    "Q1/m1 - Q2/m2": "Thermal load difference",
    "Tmax_chip1": "Chip 1 peak temperature",
    "Tmax_chip2": "Chip 2 peak temperature",
    "Rth1": "Chip 1 thermal resistance",
    "Rth2": "Chip 2 thermal resistance",
}


def build_features(parameters, fields, coords):
    Q1 = parameters[:, PARAM_IDX["Q1"]] * CHIP_AREA
    Q2 = parameters[:, PARAM_IDX["Q2"]] * CHIP_AREA
    m1 = parameters[:, PARAM_IDX["m1"]]
    m2 = parameters[:, PARAM_IDX["m2"]]
    T1 = parameters[:, PARAM_IDX["T_in1"]]
    T2 = parameters[:, PARAM_IDX["T_in2"]]
    rth1, rth2, tmax1, tmax2 = compute_rth(fields, coords, parameters)

    return {
        # Raw
        "Q1": Q1, "Q2": Q2, "m1": m1, "m2": m2, "T_in1": T1, "T_in2": T2,
        # Derived
        "Q_total": Q1 + Q2,
        "m_total": m1 + m2,
        "T_in_avg": (T1 + T2) / 2,
        "Q1 - Q2": Q1 - Q2,
        "m1 - m2": m1 - m2,
        "T_in1 - T_in2": T1 - T2,
        "Q1 / m1": Q1 / m1,
        "Q2 / m2": Q2 / m2,
        "Q1/m1 - Q2/m2": Q1 / m1 - Q2 / m2,
        # Outputs
        "Tmax_chip1": tmax1, "Tmax_chip2": tmax2,
        "Rth1": rth1, "Rth2": rth2,
    }


def main():
    parameters, fields, coords, _ = load_data()

    pca = PCA(n_components=N_MODES).fit(fields[:TRAIN_SIZE])
    coeffs = pca.transform(fields)
    var = pca.explained_variance_ratio_

    feats = build_features(parameters, fields, coords)
    n_raw, n_derived, n_out = 6, 9, 4
    names = list(feats.keys())
    sep1, sep2 = n_raw - 0.5, n_raw + n_derived - 0.5
    cat_labels = [
        ("Raw Inputs",     n_raw / 2 - 0.5),
        ("Derived Inputs", n_raw + n_derived / 2 - 0.5),
        ("Outputs",        n_raw + n_derived + n_out / 2 - 0.5),
    ]

    n_p = len(names)
    R = np.zeros((n_p, N_MODES))
    for j, n in enumerate(names):
        for i in range(N_MODES):
            R[j, i], _ = stats.pearsonr(feats[n], coeffs[:, i])

    fig = plt.figure(figsize=(16, 14))
    gs = GridSpec(1, 3, width_ratios=[5.0, 2.75, 0.15], wspace=0.0)
    ax_table = fig.add_subplot(gs[0, 0])
    ax_heat  = fig.add_subplot(gs[0, 1])
    ax_cbar  = fig.add_subplot(gs[0, 2])

    im = ax_heat.imshow(R, cmap="RdBu_r", vmin=-1, vmax=1, aspect="auto")
    ax_heat.set_xticks(range(N_MODES))
    ax_heat.set_xticklabels([f"PC{i+1}\n({var[i]*100:.1f}%)" for i in range(N_MODES)],
                            fontsize=FS - 4)
    ax_heat.xaxis.set_ticks_position("top")
    ax_heat.xaxis.set_label_position("top")
    ax_heat.set_yticks([])
    for j in range(n_p):
        for i in range(N_MODES):
            r = R[j, i]
            color = "white" if abs(r) > 0.55 else "black"
            ax_heat.text(i, j, f"{r:+.2f}", ha="center", va="center",
                         fontsize=FS - 2, color=color)
    for s in [sep1, sep2]:
        ax_heat.axhline(y=s, color="black", linewidth=2.5)

    cbar = fig.colorbar(im, cax=ax_cbar)
    cbar.set_label("Pearson $R$", fontsize=FS - 2)
    cbar.ax.tick_params(labelsize=FS - 4)

    ax_table.set_xlim(0, 1)
    ax_table.set_ylim(n_p - 0.5, -0.5)
    ax_table.axis("off")
    trans_top = blended_transform_factory(ax_table.transData, ax_table.transAxes)
    for x, h in [(0.05, "Type"), (0.34, "Description"), (0.79, "Symbol")]:
        ax_table.text(x, 1.03, h, fontsize=FS - 2, ha="center", va="bottom",
                      fontweight="bold", transform=trans_top)
    for s in [sep1, sep2]:
        ax_table.plot([0.0, 1.0], [s, s], color="black", linewidth=2.5,
                      transform=ax_table.transData, clip_on=False)
    ax_table.plot([0.10, 0.10], [-0.5, n_p - 0.5], color="gray",
                  linewidth=0.5, alpha=0.5)
    ax_table.plot([0.58, 0.58], [-0.5, n_p - 0.5], color="gray",
                  linewidth=0.5, alpha=0.5)
    for label, y_pos in cat_labels:
        ax_table.text(0.05, y_pos, label, fontsize=FS - 2, ha="center",
                      va="center", rotation=90, fontweight="bold")
    for j, n in enumerate(names):
        ax_table.text(0.12, j, DESC.get(n, n), fontsize=FS - 2,
                      ha="left", va="center")
        ax_table.text(0.60, j, LATEX.get(n, n), fontsize=FS - 2,
                      ha="left", va="center")

    PLOTS_DIR.mkdir(parents=True, exist_ok=True)
    out = PLOTS_DIR / "pearson_correlation.png"
    plt.savefig(out, dpi=300, bbox_inches="tight")
    print(f"Saved {out}")
    plt.close()


if __name__ == "__main__":
    main()
