import os
import pandas as pd
import numpy as np
from scipy.stats import entropy, wasserstein_distance

def genertare_KL_FRICHET():
    # --- Settings --- #
    methods = ["default", "gmm", "kde", "hist", "spectral"]
    csv_dir  = "CSV_output"

    # --- Dataset → target mapping --- #
    known_targets = {'abalone': 'Sex', 
                    'housing': 'SalePrice', 
                    'Accel': 'acceleration', 
                    'airfoil_self_noise': 'Frequency_Hz', 
                    'forestfires': 'area', 
                    'fuelCons': 'fuel.consumption.country',
                    'College': 'Grad.Rate',
                    'heat': 'heat', 
                    'availPwr': 'available.power', 
                    'boston': 'HousValue', 
                    'Mortgage_Dataset': '30Y-CMortgageRate', 
                    'insurance': 'charges', 
                    'avocado': 'Total Volume', 
                    'bank8FM': 'rej', 
                    'elevators': 'Goal', 
                    'diabetic_data': 'num_medications', 
                    'delta_ail': 'RollRate',
                    'delta_elv': 'climbRate', 
                    'maxTorque': 'maximal.torque', 
                    'house': 'Price', 
                    'triazine_combined': 'activity', 
                    'red_wine': 'quality',
                    'Puma32h_Dataset': 'thetadd6', 
                    'a1': 'a1',  'a2': 'a2', 'a3': 'a3', 'a4': 'a4', 'a6': 'a6', 'a7': 'a7', 
                    'california': 'MedianHouseValue',
                    'cpuSm': 'usr',
                    'Treasury_Dataset': '1MonthCDRate', 
                    'SF_Salaries': 'TotalPayBenefits'}

    def compute_kl(p, q):
        p = np.array(p) + 1e-8
        q = np.array(q) + 1e-8
        p /= p.sum()
        q /= q.sum()
        return entropy(p, q)

    def get_blocks(phi_vals, target_vals, rel):
        """
        rel==0 → central (min-φ) cluster
        rel==1 → both tails (max-φ and its near-duplicates)
        else   → exact φ-match

        Returns a list of (min, max) for each contiguous block in target-sorted order.
        """
        phi  = np.array(phi_vals, dtype=float)
        targ = np.array(target_vals, dtype=float)

        # sort by the target so blocks correspond to true x-intervals
        order = np.argsort(targ)
        phi   = phi[order]
        targ  = targ[order]

        # find unique φ-values to set a dynamic tolerance
        uniq = np.unique(phi)
        tiny = 1e-8

        if rel == 0:
            level = uniq[0]
            # tol = gap to the next φ
            tol   = (uniq[1] - level) + tiny if uniq.size > 1 else tiny
            mask  = phi <= level + tol

        elif rel == 1:
            level = uniq[-1]
            # tol = gap down to the second-highest φ
            tol   = (level - uniq[-2]) + tiny if uniq.size > 1 else tiny
            mask  = phi >= level - tol

        else:
            level = rel
            tol   = tiny
            mask  = np.isclose(phi, level, atol=tol)

        # if nothing matches, return empty list
        if not mask.any():
            return []

        # scan for contiguous True runs
        blocks = []
        in_run = False
        for i, m in enumerate(mask):
            if m and not in_run:
                in_run   = True
                start_ix = i
            elif not m and in_run:
                seg = targ[start_ix:i]
                blocks.append((seg.min(), seg.max()))
                in_run = False
        if in_run:
            seg = targ[start_ix:]
            blocks.append((seg.min(), seg.max()))

        return blocks

    # --- Load and group your files --- #
    datasets = {}
    for fn in os.listdir(csv_dir):
        if not fn.endswith(".csv"): continue
        base, method = fn[:-4].split("_phi_")
        if method == "manual": continue
        datasets.setdefault(base, {})[method] = os.path.join(csv_dir, fn)

    # --- Build the comparison table --- #
    rows = []
    for ds, files in datasets.items():
        if "default" not in files: continue

        df0 = pd.read_csv(files["default"])
        if "phi" not in df0: continue

        target_col = known_targets.get(
            ds,
            next((c for c in df0.columns if c != "phi"), None)
        )
        if not target_col: continue

        row = {
            "Dataset": ds,
            "Rows":    len(df0),
            "Cols":    len(df0.columns)
        }

        for m in methods:
            if m == "default" or m not in files: continue

            dfm = pd.read_csv(files[m])
            kl  = compute_kl(df0["phi"], dfm["phi"])
            fr  = wasserstein_distance(df0["phi"], dfm["phi"])

            b0 = get_blocks(dfm["phi"], dfm[target_col], 0)
            b1 = get_blocks(dfm["phi"], dfm[target_col], 1)

            fmt = lambda bl: (
                "[" +
                ", ".join(f"[{lo:.2f}, {hi:.2f}]" for lo, hi in bl) +
                "]"
            ) if bl else "-"

            row.update({
                f"{m}_KL":       round(float(kl), 4),
                f"{m}_Fréchet":  round(float(fr), 4),
                # f"{m}_Rel=0":    fmt(b0),
                # f"{m}_Rel=1":    fmt(b1),
            })

        rows.append(row)

    pd.DataFrame(rows).to_csv("KL_FRICHET_comparison_summary.csv", index=False)
    print("Comparison summary saved to: comparison_summary.csv")


