#!/usr/bin/env python3
"""Create a reader-facing CGMsum measurement table without altering frozen v19 CSVs."""

from __future__ import annotations

import csv
import hashlib
from pathlib import Path

ROOT = Path(__file__).resolve().parent
SOURCE = (
    ROOT.parent
    / "independent_cgm_results_v19_mos14to20keV_excluded_hi4pi_nh_per_pointing"
    / "independent_cgm_v19_primary_dual_mos_measurements.csv"
)
OUTPUT = ROOT / "m31_cgmsum_v19_primary_measurements_public.csv"
DICTIONARY = ROOT / "m31_cgmsum_v19_primary_measurements_data_dictionary.md"

ALIASES = {
    "cgmsum_kt_keV": "mwhalo_kt_keV",
    "cgmsum_kt_err_keV": "mwhalo_kt_err_keV",
    "cgmsum_norm": "mwhalo_norm",
    "cgmsum_norm_err": "mwhalo_norm_err",
    "cgmsum_cov_kt_norm": "mwhalo_cov_kt_norm",
    "v18_cgmsum_kt_keV": "v18_mwhalo_kt_keV",
    "v18_cgmsum_kt_err_keV": "v18_mwhalo_kt_err_keV",
    "v18_cgmsum_norm": "v18_mwhalo_norm",
}


def generate(
    source: Path = SOURCE,
    output: Path = OUTPUT,
    dictionary: Path = DICTIONARY,
) -> int:
    resolved_paths = {
        "source": source.resolve(),
        "output": output.resolve(),
        "dictionary": dictionary.resolve(),
    }
    if len(set(resolved_paths.values())) != len(resolved_paths):
        raise ValueError(
            "source, output, and dictionary paths must be distinct: "
            f"{resolved_paths}"
        )

    with source.open(newline="") as handle:
        reader = csv.DictReader(handle)
        rows = list(reader)
        fieldnames = list(reader.fieldnames or [])

    if len(rows) != 14:
        raise ValueError(f"expected 14 primary fields, found {len(rows)}")
    missing = sorted(set(ALIASES.values()) - set(fieldnames))
    if missing:
        raise ValueError(f"historical source fields are missing: {missing}")

    output_fields = [*fieldnames, *ALIASES]
    for row in rows:
        for alias, historical in ALIASES.items():
            row[alias] = row[historical]

    output.parent.mkdir(parents=True, exist_ok=True)
    temporary = output.with_suffix(".tmp")
    with temporary.open("w", newline="") as handle:
        writer = csv.DictWriter(handle, fieldnames=output_fields)
        writer.writeheader()
        writer.writerows(rows)
    temporary.replace(output)

    dictionary_lines = [
        "# M31 CGMsum v19 primary-measurement data dictionary",
        "",
        "This reader-facing table contains the 14 primary dual-MOS fields.",
        f"Frozen source file: `{source.name}`.",
        f"Frozen source SHA-256: `{hashlib.sha256(source.read_bytes()).hexdigest()}`.",
        "The `cgmsum_*` columns are the preferred public fields. The corresponding",
        "`mwhalo_*` columns are retained unchanged as historical frozen-fit fields",
        "for provenance; each alias is byte-for-byte equal to its historical source.",
        "No fit, flux, quality flag, or frozen source CSV is modified.",
        "",
        "| Preferred public field | Historical frozen-fit field |",
        "|---|---|",
    ]
    dictionary_lines.extend(
        f"| `{alias}` | `{historical}` |" for alias, historical in ALIASES.items()
    )
    dictionary_lines.extend(
        [
            "",
            "The historical component name does not establish a Milky-Way distance.",
            "Throughout the manuscript, CGMsum denotes the directly measured cool",
            "line-of-sight component, potentially containing MW, M31, and named",
            "Local-Group contributions.",
            "",
        ]
    )
    dictionary.parent.mkdir(parents=True, exist_ok=True)
    dictionary_temporary = dictionary.with_suffix(".tmp")
    dictionary_temporary.write_text("\n".join(dictionary_lines))
    dictionary_temporary.replace(dictionary)
    return len(rows)


if __name__ == "__main__":
    count = generate()
    print(f"Wrote {OUTPUT} ({count} rows)")
    print(f"Wrote {DICTIONARY}")
