#!/usr/bin/env python3
"""Validate the prepared real SPARC corpus and prove chambers were not run."""

from __future__ import annotations

import argparse
import json
import sys
from pathlib import Path

import numpy as np
import pandas as pd


def parse_args() -> argparse.Namespace:
    root = Path(__file__).resolve().parents[1]
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("--project-root", type=Path, default=root)
    return parser.parse_args()


def main() -> int:
    root = parse_args().project_root.resolve()
    prep = root / "data/prepared_profiles"
    profiles = pd.read_csv(prep / "galaxy_profiles.csv", float_precision="round_trip")
    galaxies = pd.read_csv(prep / "sparc_galaxies.csv", float_precision="round_trip")
    exclusions = pd.read_csv(prep / "sparc_point_exclusions.csv", float_precision="round_trip")
    crosscheck = pd.read_csv(prep / "rotmod_crosscheck.csv", float_precision="round_trip")
    summary = json.loads((prep / "sparc_preparation_summary.json").read_text(encoding="utf-8"))

    errors: list[str] = []
    if len(profiles) != 3389:
        errors.append(f"valid radial rows: expected 3389, found {len(profiles)}")
    if len(exclusions) != 2:
        errors.append(f"excluded radial rows: expected 2, found {len(exclusions)}")
    if len(galaxies) != 175 or galaxies["galaxy_id"].nunique() != 175:
        errors.append("galaxy table is not 175 unique galaxies")
    if len(crosscheck) != 175 or not (crosscheck["status"] == "EXACT_MATCH").all():
        errors.append("Rotmod ZIP cross-check is not 175 exact matches")
    if not profiles["valid_point"].astype(bool).all():
        errors.append("prepared profile contains invalid point")
    if profiles.duplicated(["galaxy_id", "radius_kpc"]).any():
        errors.append("duplicate galaxy-radius row")
    for column in ["radius_kpc", "g_bar", "g_obs", "log10_g_bar", "log10_g_obs"]:
        values = pd.to_numeric(profiles[column], errors="coerce").to_numpy(dtype=float)
        if not np.isfinite(values).all():
            errors.append(f"{column}: nonfinite values")
    if not (profiles[["radius_kpc", "g_bar", "g_obs"]] > 0).all().all():
        errors.append("nonpositive prepared radius or acceleration")
    if int(galaxies["is_primary"].astype(bool).sum()) != 121:
        errors.append("PRIMARY count is not 121")
    if int(galaxies["is_inclination_sensitivity"].astype(bool).sum()) != 115:
        errors.append("INCLINATION_SENSITIVITY count is not 115")
    if int(galaxies["is_resolution_sensitivity"].astype(bool).sum()) != 75:
        errors.append("RESOLUTION_SENSITIVITY count is not 75")
    if int(galaxies["is_strict_sensitivity"].astype(bool).sum()) != 74:
        errors.append("STRICT_SENSITIVITY count is not 74")
    if summary.get("chambers_run") is not False:
        errors.append("summary does not explicitly record chambers_run=false")

    export_files = [
        path for path in (root / "chambers/exports").rglob("*")
        if path.is_file() and path.name.lower() != "readme.md"
    ]
    if export_files:
        errors.append(f"chamber export files unexpectedly present: {[str(p) for p in export_files]}")

    if errors:
        print("SPARC PREPARATION VALIDATION FAILED", file=sys.stderr)
        print("\n".join(errors), file=sys.stderr)
        return 2
    print("PASS: real SPARC corpus prepared from 3 local source files")
    print("PASS: 175 galaxies, 3389 valid radial rows, 2 documented point exclusions")
    print("PASS: 175 individual Rotmod files exactly match the combined mass-model table")
    print("PASS: no chamber output or chamber execution is present")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
