#!/usr/bin/env python3
"""
Auto-generated by submit_fisher_condor.py.
Merges per-job Fisher CSVs, renders a LaTeX table, and writes a
summary table (baseline + alt-memory + nearby + Bayesian placeholder).

Usage:
    python merge_results.py
    python merge_results.py --N-near 100
    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"/data/www.astro/chrism/newcos/fisher_run46")
FISHER_SCRIPT = pathlib.Path(r"/home/chrism/cosmem/fisher_population_table.py")
GENDAG_SCRIPT = pathlib.Path(r"/home/chrism/cosmem/fisher_gendag.py")
PYTHONPATH    = r""

CSV_FILES = [
    r"/data/www.astro/chrism/newcos/fisher_run46/jobs/aLIGO_HLV_baseline/scenario_0000/fisher_table.csv",
    r"/data/www.astro/chrism/newcos/fisher_run46/jobs/aLIGO_HLV_var01/scenario_0001/fisher_table.csv",
    r"/data/www.astro/chrism/newcos/fisher_run46/jobs/aLIGO_HLV_var02/scenario_0002/fisher_table.csv",
    r"/data/www.astro/chrism/newcos/fisher_run46/jobs/aLIGO_HLV_var03/scenario_0003/fisher_table.csv",
    r"/data/www.astro/chrism/newcos/fisher_run46/jobs/aLIGO_HLV_var04/scenario_0004/fisher_table.csv",
    r"/data/www.astro/chrism/newcos/fisher_run46/jobs/aLIGO_HLV_var05/scenario_0005/fisher_table.csv",
    r"/data/www.astro/chrism/newcos/fisher_run46/jobs/aLIGO_HLV_var06/scenario_0006/fisher_table.csv",
    r"/data/www.astro/chrism/newcos/fisher_run46/jobs/aLIGO_HLV_var07/scenario_0007/fisher_table.csv",
    r"/data/www.astro/chrism/newcos/fisher_run46/jobs/aLIGO_HLV_var08/scenario_0008/fisher_table.csv",
    r"/data/www.astro/chrism/newcos/fisher_run46/jobs/aLIGO_HLV_dLnear700/fisher_table.csv",
    r"/data/www.astro/chrism/newcos/fisher_run46/jobs/ET_baseline/scenario_0000/fisher_table.csv",
    r"/data/www.astro/chrism/newcos/fisher_run46/jobs/ET_var01/scenario_0001/fisher_table.csv",
    r"/data/www.astro/chrism/newcos/fisher_run46/jobs/ET_var02/scenario_0002/fisher_table.csv",
    r"/data/www.astro/chrism/newcos/fisher_run46/jobs/ET_var03/scenario_0003/fisher_table.csv",
    r"/data/www.astro/chrism/newcos/fisher_run46/jobs/ET_var04/scenario_0004/fisher_table.csv",
    r"/data/www.astro/chrism/newcos/fisher_run46/jobs/ET_var05/scenario_0005/fisher_table.csv",
    r"/data/www.astro/chrism/newcos/fisher_run46/jobs/ET_var06/scenario_0006/fisher_table.csv",
    r"/data/www.astro/chrism/newcos/fisher_run46/jobs/ET_var07/scenario_0007/fisher_table.csv",
    r"/data/www.astro/chrism/newcos/fisher_run46/jobs/ET_var08/scenario_0008/fisher_table.csv",
    r"/data/www.astro/chrism/newcos/fisher_run46/jobs/ET_dLnear700/fisher_table.csv",
    r"/data/www.astro/chrism/newcos/fisher_run46/jobs/CE_baseline/scenario_0000/fisher_table.csv",
    r"/data/www.astro/chrism/newcos/fisher_run46/jobs/CE_var01/scenario_0001/fisher_table.csv",
    r"/data/www.astro/chrism/newcos/fisher_run46/jobs/CE_var02/scenario_0002/fisher_table.csv",
    r"/data/www.astro/chrism/newcos/fisher_run46/jobs/CE_var03/scenario_0003/fisher_table.csv",
    r"/data/www.astro/chrism/newcos/fisher_run46/jobs/CE_var04/scenario_0004/fisher_table.csv",
    r"/data/www.astro/chrism/newcos/fisher_run46/jobs/CE_var05/scenario_0005/fisher_table.csv",
    r"/data/www.astro/chrism/newcos/fisher_run46/jobs/CE_var06/scenario_0006/fisher_table.csv",
    r"/data/www.astro/chrism/newcos/fisher_run46/jobs/CE_var07/scenario_0007/fisher_table.csv",
    r"/data/www.astro/chrism/newcos/fisher_run46/jobs/CE_var08/scenario_0008/fisher_table.csv",
    r"/data/www.astro/chrism/newcos/fisher_run46/jobs/CE_dLnear700/fisher_table.csv",
    r"/data/www.astro/chrism/newcos/fisher_run46/jobs/ET_CE_baseline/scenario_0000/fisher_table.csv",
    r"/data/www.astro/chrism/newcos/fisher_run46/jobs/ET_CE_var01/scenario_0001/fisher_table.csv",
    r"/data/www.astro/chrism/newcos/fisher_run46/jobs/ET_CE_var02/scenario_0002/fisher_table.csv",
    r"/data/www.astro/chrism/newcos/fisher_run46/jobs/ET_CE_var03/scenario_0003/fisher_table.csv",
    r"/data/www.astro/chrism/newcos/fisher_run46/jobs/ET_CE_var04/scenario_0004/fisher_table.csv",
    r"/data/www.astro/chrism/newcos/fisher_run46/jobs/ET_CE_var05/scenario_0005/fisher_table.csv",
    r"/data/www.astro/chrism/newcos/fisher_run46/jobs/ET_CE_var06/scenario_0006/fisher_table.csv",
    r"/data/www.astro/chrism/newcos/fisher_run46/jobs/ET_CE_var07/scenario_0007/fisher_table.csv",
    r"/data/www.astro/chrism/newcos/fisher_run46/jobs/ET_CE_var08/scenario_0008/fisher_table.csv",
    r"/data/www.astro/chrism/newcos/fisher_run46/jobs/ET_CE_dLnear700/fisher_table.csv",
    r"/data/www.astro/chrism/newcos/fisher_run46/jobs/LISA_light_seeds_baseline/scenario_0000/fisher_table.csv",
    r"/data/www.astro/chrism/newcos/fisher_run46/jobs/LISA_light_seeds_var01/scenario_0001/fisher_table.csv",
    r"/data/www.astro/chrism/newcos/fisher_run46/jobs/LISA_light_seeds_var02/scenario_0002/fisher_table.csv",
    r"/data/www.astro/chrism/newcos/fisher_run46/jobs/LISA_light_seeds_var03/scenario_0003/fisher_table.csv",
    r"/data/www.astro/chrism/newcos/fisher_run46/jobs/LISA_light_seeds_var04/scenario_0004/fisher_table.csv",
    r"/data/www.astro/chrism/newcos/fisher_run46/jobs/LISA_heavy_seeds_baseline/scenario_0000/fisher_table.csv",
    r"/data/www.astro/chrism/newcos/fisher_run46/jobs/LISA_heavy_seeds_var01/scenario_0001/fisher_table.csv",
    r"/data/www.astro/chrism/newcos/fisher_run46/jobs/LISA_heavy_seeds_var02/scenario_0002/fisher_table.csv",
    r"/data/www.astro/chrism/newcos/fisher_run46/jobs/LISA_heavy_seeds_var03/scenario_0003/fisher_table.csv",
    r"/data/www.astro/chrism/newcos/fisher_run46/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)
    p.add_argument("--csv-glob",      default=None)
    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_mod(script_path, 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("_mod", script_path)
    mod  = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(mod)
    return mod


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}")

    # Legacy full OAT table via fisher_population_table.py (fisher_combined.tex)
    if fscript.exists():
        try:
            mod = _load_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)

    # Paper tables: table_full_results.tex and table_main_results.tex
    # Delegated to fisher_gendag.py so LaTeX strings are not embedded in an f-string.
    try:
        gendag_mod = _load_mod(GENDAG_SCRIPT)
        gendag_mod.write_full_results_table(combined, outdir, N_near=args.N_near)
        gendag_mod.write_main_results_table(combined, outdir)
        gendag_mod.write_summary_table(combined, outdir)
    except Exception as exc:
        import traceback
        print(f"Table generation failed: {exc}", file=sys.stderr)
        traceback.print_exc(file=sys.stderr)

    print("\nMerge complete.")


if __name__ == "__main__":
    main()
