#!/usr/bin/env python3
"""
Auto-generated by submit_fisher_condor.py.
Merges per-job Fisher CSVs and renders a compact LaTeX table.

Usage:
    python merge_results.py
    python merge_results.py --N-near 100   # change nearby-event target
    python merge_results.py --csv-glob "/path/**/fisher_table.csv"
"""
import argparse, importlib.util, math, os, pathlib, sys
import numpy as np
import pandas as pd

OUTDIR        = pathlib.Path(r"/home/chrism/cosmem/fisher_run21")
FISHER_SCRIPT = pathlib.Path(r"/home/chrism/cosmem/fisher_population_table.py")
PYTHONPATH    = r""

CSV_FILES = [
    r"/home/chrism/cosmem/fisher_run21/jobs/aLIGO_HLV_baseline/scenario_0000/fisher_table.csv",
    r"/home/chrism/cosmem/fisher_run21/jobs/aLIGO_HLV_var01/scenario_0001/fisher_table.csv",
    r"/home/chrism/cosmem/fisher_run21/jobs/aLIGO_HLV_var02/scenario_0002/fisher_table.csv",
    r"/home/chrism/cosmem/fisher_run21/jobs/aLIGO_HLV_var03/scenario_0003/fisher_table.csv",
    r"/home/chrism/cosmem/fisher_run21/jobs/aLIGO_HLV_var04/scenario_0004/fisher_table.csv",
    r"/home/chrism/cosmem/fisher_run21/jobs/aLIGO_HLV_var05/scenario_0005/fisher_table.csv",
    r"/home/chrism/cosmem/fisher_run21/jobs/aLIGO_HLV_var06/scenario_0006/fisher_table.csv",
    r"/home/chrism/cosmem/fisher_run21/jobs/aLIGO_HLV_var07/scenario_0007/fisher_table.csv",
    r"/home/chrism/cosmem/fisher_run21/jobs/aLIGO_HLV_var08/scenario_0008/fisher_table.csv",
    r"/home/chrism/cosmem/fisher_run21/jobs/ET_baseline/scenario_0000/fisher_table.csv",
    r"/home/chrism/cosmem/fisher_run21/jobs/ET_var01/scenario_0001/fisher_table.csv",
    r"/home/chrism/cosmem/fisher_run21/jobs/ET_var02/scenario_0002/fisher_table.csv",
    r"/home/chrism/cosmem/fisher_run21/jobs/ET_var03/scenario_0003/fisher_table.csv",
    r"/home/chrism/cosmem/fisher_run21/jobs/ET_var04/scenario_0004/fisher_table.csv",
    r"/home/chrism/cosmem/fisher_run21/jobs/ET_var05/scenario_0005/fisher_table.csv",
    r"/home/chrism/cosmem/fisher_run21/jobs/ET_var06/scenario_0006/fisher_table.csv",
    r"/home/chrism/cosmem/fisher_run21/jobs/ET_var07/scenario_0007/fisher_table.csv",
    r"/home/chrism/cosmem/fisher_run21/jobs/ET_var08/scenario_0008/fisher_table.csv",
    r"/home/chrism/cosmem/fisher_run21/jobs/CE_baseline/scenario_0000/fisher_table.csv",
    r"/home/chrism/cosmem/fisher_run21/jobs/CE_var01/scenario_0001/fisher_table.csv",
    r"/home/chrism/cosmem/fisher_run21/jobs/CE_var02/scenario_0002/fisher_table.csv",
    r"/home/chrism/cosmem/fisher_run21/jobs/CE_var03/scenario_0003/fisher_table.csv",
    r"/home/chrism/cosmem/fisher_run21/jobs/CE_var04/scenario_0004/fisher_table.csv",
    r"/home/chrism/cosmem/fisher_run21/jobs/CE_var05/scenario_0005/fisher_table.csv",
    r"/home/chrism/cosmem/fisher_run21/jobs/CE_var06/scenario_0006/fisher_table.csv",
    r"/home/chrism/cosmem/fisher_run21/jobs/CE_var07/scenario_0007/fisher_table.csv",
    r"/home/chrism/cosmem/fisher_run21/jobs/CE_var08/scenario_0008/fisher_table.csv",
    r"/home/chrism/cosmem/fisher_run21/jobs/ET_CE_baseline/scenario_0000/fisher_table.csv",
    r"/home/chrism/cosmem/fisher_run21/jobs/ET_CE_var01/scenario_0001/fisher_table.csv",
    r"/home/chrism/cosmem/fisher_run21/jobs/ET_CE_var02/scenario_0002/fisher_table.csv",
    r"/home/chrism/cosmem/fisher_run21/jobs/ET_CE_var03/scenario_0003/fisher_table.csv",
    r"/home/chrism/cosmem/fisher_run21/jobs/ET_CE_var04/scenario_0004/fisher_table.csv",
    r"/home/chrism/cosmem/fisher_run21/jobs/ET_CE_var05/scenario_0005/fisher_table.csv",
    r"/home/chrism/cosmem/fisher_run21/jobs/ET_CE_var06/scenario_0006/fisher_table.csv",
    r"/home/chrism/cosmem/fisher_run21/jobs/ET_CE_var07/scenario_0007/fisher_table.csv",
    r"/home/chrism/cosmem/fisher_run21/jobs/ET_CE_var08/scenario_0008/fisher_table.csv",
    r"/home/chrism/cosmem/fisher_run21/jobs/LISA_light_seeds_baseline/scenario_0000/fisher_table.csv",
    r"/home/chrism/cosmem/fisher_run21/jobs/LISA_light_seeds_var01/scenario_0001/fisher_table.csv",
    r"/home/chrism/cosmem/fisher_run21/jobs/LISA_light_seeds_var02/scenario_0002/fisher_table.csv",
    r"/home/chrism/cosmem/fisher_run21/jobs/LISA_light_seeds_var03/scenario_0003/fisher_table.csv",
    r"/home/chrism/cosmem/fisher_run21/jobs/LISA_light_seeds_var04/scenario_0004/fisher_table.csv",
    r"/home/chrism/cosmem/fisher_run21/jobs/LISA_heavy_seeds_baseline/scenario_0000/fisher_table.csv",
    r"/home/chrism/cosmem/fisher_run21/jobs/LISA_heavy_seeds_var01/scenario_0001/fisher_table.csv",
    r"/home/chrism/cosmem/fisher_run21/jobs/LISA_heavy_seeds_var02/scenario_0002/fisher_table.csv",
    r"/home/chrism/cosmem/fisher_run21/jobs/LISA_heavy_seeds_var03/scenario_0003/fisher_table.csv",
    r"/home/chrism/cosmem/fisher_run21/jobs/LISA_heavy_seeds_var04/scenario_0004/fisher_table.csv",
]


def parse_args():
    p = argparse.ArgumentParser(description=__doc__,
                                formatter_class=argparse.RawDescriptionHelpFormatter)
    p.add_argument("--outdir",        default=None)
    p.add_argument("--fisher-script", default=None)
    p.add_argument("--N-near",        type=int, default=100,
                   help="Events at dL_near for sigma_near column (default: 100)")
    p.add_argument("--csv-glob",      default=None,
                   help="Glob to find CSVs instead of hard-coded list")
    return p.parse_args()


def load_csvs(files):
    dfs, missing = [], []
    for p in files:
        p = pathlib.Path(p)
        if p.exists():
            dfs.append(pd.read_csv(p))
        else:
            missing.append(str(p))
    if missing:
        print(f"WARNING: {len(missing)} CSV(s) not found:", file=sys.stderr)
        for m in missing: print(f"  {m}", file=sys.stderr)
    if not dfs:
        sys.exit("No job outputs found.")
    combined = pd.concat(dfs, ignore_index=True)
    print(f"Loaded {len(dfs)} CSVs  ({len(combined)} rows)")
    for det in combined["detector"].unique():
        print(f"  {det}: {len(combined[combined['detector']==det])} rows")
    return combined


def load_fisher_mod(fisher_script, pythonpath=None):
    for _p in [pythonpath or ""] + os.environ.get("PYTHONPATH","").split(os.pathsep):
        if _p and _p not in sys.path:
            sys.path.insert(0, _p)
    spec = importlib.util.spec_from_file_location("fisher_pop", fisher_script)
    mod  = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(mod)
    return mod


def print_summary(combined, N_near):
    print()
    print(f"Summary — baseline rows  (sigma km/s/Mpc, N_near={N_near})")
    print("-" * 70)
    has_ext = "sigma_ext_lo" in combined.columns
    for det in combined["detector"].unique():
        row   = combined[combined["detector"]==det].iloc[0]
        sigma = float(row.get("sigma_H0", float("nan")))
        N_det = float(row.get("N_det",    float("nan")))
        try:
            s_near = sigma * math.sqrt(N_det / N_near) if (
                np.isfinite(sigma) and N_det > 0) else float("nan")
        except Exception:
            s_near = float("nan")
        line = (f"  {det:<12}  N_det={int(N_det) if np.isfinite(N_det) else '?':>5}"
                f"  sigma(N={N_near})={s_near:.2f}")
        if has_ext:
            lo = float(row.get("sigma_ext_lo", float("nan")))
            hi = float(row.get("sigma_ext_hi", float("nan")))
            line += f"  sigma(N_lo)={lo:.2f}  sigma(N_hi)={hi:.3f}"
        print(line)


def main():
    args   = parse_args()
    outdir = pathlib.Path(args.outdir) if args.outdir else OUTDIR
    fscript = pathlib.Path(args.fisher_script) if args.fisher_script else FISHER_SCRIPT
    outdir.mkdir(parents=True, exist_ok=True)

    if args.csv_glob:
        import glob
        files = sorted(glob.glob(args.csv_glob, recursive=True))
        if not files: sys.exit(f"No files matched: {args.csv_glob}")
    else:
        files = CSV_FILES

    combined = load_csvs(files)

    out_csv = outdir / "fisher_combined.csv"
    combined.to_csv(out_csv, index=False)
    print(f"Saved: {out_csv}")

    if fscript.exists():
        try:
            mod = load_fisher_mod(fscript, PYTHONPATH)
            tex = mod.format_combined_latex_table(combined, N_near=args.N_near)
            tex_path = outdir / "fisher_combined.tex"
            tex_path.write_text(tex)
            print(f"Saved: {tex_path}")
        except Exception as exc:
            import traceback
            print(f"LaTeX render failed: {exc}", file=sys.stderr)
            traceback.print_exc(file=sys.stderr)
    else:
        print(f"WARNING: Fisher script not found at {fscript}", file=sys.stderr)

    print_summary(combined, args.N_near)
    print("\nMerge complete.")


if __name__ == "__main__":
    main()
