#!/usr/bin/env python3
"""
Rebuild county representative-point GHI summaries from cached NSRDB raw CSV responses.

This does not call the NSRDB API. It reads data/nrel/representative_point_csv/*.csv, computes:

avgSolarGhiKwhM2Day = sum(hourly GHI) / 1000 / 365

and writes a county-keyed CSV compatible with build_county_climate_data.py.
"""

from __future__ import annotations

import argparse
import csv
from pathlib import Path


DEFAULT_POINTS_CSV = Path("data/nrel/county_representative_points.csv")
DEFAULT_REPRESENTATIVE_POINT_CSV_DIR = Path("data/nrel/representative_point_csv")
DEFAULT_OUTPUT_CSV = Path("data/nrel/county_representative_point_ghi_summary.csv")


def read_county_points(points_csv: Path) -> list[dict[str, str]]:
    """Read county representative points keyed by county FIPS."""
    with points_csv.open(newline="", encoding="utf-8") as handle:
        return list(csv.DictReader(handle))


def extract_ghi_values(csv_path: Path) -> list[float]:
    """Extract numeric hourly GHI values from a cached NSRDB CSV response."""
    with csv_path.open(newline="", encoding="utf-8-sig") as handle:
        reader = csv.reader(handle)
        ghi_index: int | None = None
        values: list[float] = []

        for row in reader:
            if ghi_index is None:
                if {"Year", "Month", "Day", "Hour", "Minute", "GHI"}.issubset(set(row)):
                    ghi_index = row.index("GHI")
                continue

            if len(row) <= ghi_index or not row[ghi_index].strip():
                continue
            values.append(float(row[ghi_index]))

    if ghi_index is None:
        raise ValueError(f"Could not find NSRDB data header with a GHI column in {csv_path}.")
    if not values:
        raise ValueError(f"No GHI values were found in {csv_path}.")
    return values


def select_raw_csv(representative_point_csv_dir: Path, county_fips: str) -> Path | None:
    """Return the cached raw CSV for a county, preferring polar data when both exist."""
    matches = sorted(representative_point_csv_dir.glob(f"{county_fips}_*_ghi.csv"))
    if not matches:
        return None

    polar_matches = [path for path in matches if "_polar-tmy_" in path.name]
    return polar_matches[0] if polar_matches else matches[0]


def source_label(raw_csv: Path) -> str:
    """Return a readable source label from the cached filename."""
    if "_polar-tmy_" in raw_csv.name:
        return "NSRDB Polar TMY PSM v4 representative point"
    if "_goes-tmy_" in raw_csv.name:
        return "NSRDB GOES TMY PSM v4 representative point"
    return "NSRDB TMY representative point"


def summarize_county(point: dict[str, str], raw_csv: Path) -> dict[str, str]:
    """Summarize one county raw CSV into the app solar metric."""
    ghi_values = extract_ghi_values(raw_csv)
    avg_daily_ghi = sum(ghi_values) / 1000 / 365

    return {
        "county_fips": point["county_fips"],
        "county_name": point["county_name"],
        "state_fips": point["state_fips"],
        "state_abbr": point["state_abbr"],
        "lat": point["lat"],
        "lon": point["lon"],
        "avgSolarGhiKwhM2Day": f"{avg_daily_ghi:.3f}",
        "ghi_rows": str(len(ghi_values)),
        "ghi_min": f"{min(ghi_values):.1f}",
        "ghi_max": f"{max(ghi_values):.1f}",
        "source": source_label(raw_csv),
        "raw_csv": str(raw_csv),
    }


def write_summary_csv(rows: list[dict[str, str]], output_csv: Path) -> None:
    """Write rebuilt county solar summaries."""
    output_csv.parent.mkdir(parents=True, exist_ok=True)
    with output_csv.open("w", newline="", encoding="utf-8") as handle:
        writer = csv.DictWriter(
            handle,
            fieldnames=[
                "county_fips",
                "county_name",
                "state_fips",
                "state_abbr",
                "lat",
                "lon",
                "avgSolarGhiKwhM2Day",
                "ghi_rows",
                "ghi_min",
                "ghi_max",
                "source",
                "raw_csv",
            ],
        )
        writer.writeheader()
        writer.writerows(rows)


def parse_args() -> argparse.Namespace:
    """Parse command-line arguments."""
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("--points-csv", type=Path, default=DEFAULT_POINTS_CSV)
    parser.add_argument(
        "--representative-point-csv-dir",
        dest="representative_point_csv_dir",
        type=Path,
        default=DEFAULT_REPRESENTATIVE_POINT_CSV_DIR,
    )
    parser.add_argument("--output-csv", type=Path, default=DEFAULT_OUTPUT_CSV)
    return parser.parse_args()


def main() -> None:
    """Run the cached raw CSV summarizer."""
    args = parse_args()
    rows: list[dict[str, str]] = []
    missing: list[str] = []
    failed: list[str] = []

    for point in read_county_points(args.points_csv):
        county_fips = point["county_fips"]
        raw_csv = select_raw_csv(args.representative_point_csv_dir, county_fips)
        if raw_csv is None:
            missing.append(county_fips)
            continue

        try:
            rows.append(summarize_county(point, raw_csv))
        except (OSError, ValueError) as exc:
            failed.append(f"{county_fips}: {exc}")

    write_summary_csv(rows, args.output_csv)
    print(f"Wrote {len(rows)} county representative-point solar summaries to {args.output_csv}")
    if missing:
        print(f"Missing raw CSVs for {len(missing)} counties: {', '.join(missing[:20])}")
    if failed:
        print(f"Failed to summarize {len(failed)} counties:")
        for message in failed[:20]:
            print(f"  {message}")


if __name__ == "__main__":
    main()
