"""Read-only structural and solar consistency report for the supplied dataset."""

import argparse
import csv
import json
from datetime import date, datetime, timedelta
from pathlib import Path
from typing import Optional, Sequence

from mountain_twin.solar.sun_engine import solar_position


def read_rows(path: Path) -> list[dict[str, str]]:
    """Read a CSV with named columns."""
    with path.open(newline="", encoding="utf-8") as stream:
        return list(csv.DictReader(stream))


def main(argv: Optional[Sequence[str]] = None) -> int:
    """Print checks; return 1 for invalid structure, 0 with legacy solar warnings."""
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument(
        "--root", type=Path, default=Path.cwd(), help="Repository root (default: current directory)"
    )
    args = parser.parse_args(argv)
    try:
        manifest = json.loads((args.root / "manifest.json").read_text())
        processed = args.root / "data" / "processed"
        routes = read_rows(processed / "routes_summary.csv")
        tmb = read_rows(processed / "tmb_routes_summary.csv")
        solar = read_rows(processed / "tmb_solar_windows_v0.1.csv")
        points = read_rows(processed / "trail_points_master.csv")
        expected = {str(i + 1): str(date(2026, 7, 2) + timedelta(days=i)) for i in range(9)}
        checks = {
            "16 routes and nine TMB stages": len(routes) == 16 and len(tmb) == 9,
            "TMB dates July 2–10, 2026": {r["tmb_day"]: r["assigned_hike_date"] for r in tmb}
            == expected,
            "nine matching solar dates": len(solar) == 9
            and {r["tmb_day"]: r["date"] for r in solar} == expected,
            "point count matches route summaries": len(points)
            == sum(int(r["points"]) for r in routes),
            "distance matches manifest (rounding tolerance 0.01 km)": abs(
                sum(float(r["distance_km"]) for r in tmb) - manifest["tmb_distance_km"]
            )
            < 0.01,
            "actual TMB clock times unavailable": manifest["actual_tmb_clock_times_available"]
            is False,
            "solar model excludes terrain shadows": all(
                r["terrain_shadow_included"] == "no" and r["model"] == "astronomical_horizon_only"
                for r in solar
            ),
        }
        print("Mountain Twin v0.1 validation (read-only)")
        for label, passed in checks.items():
            print(f"{'PASS' if passed else 'FAIL'}: {label}")
        print(
            f"{len(points):,} trail points; TMB distance {sum(float(r['distance_km']) for r in tmb):.3f} km"
        )
        for row in solar:
            el, az = solar_position(
                datetime.fromisoformat(row["solar_noon_local"]),
                float(row["representative_lat"]),
                float(row["representative_lon"]),
            )
            error = abs((az - float(row["solar_noon_azimuth_deg"]) + 180) % 360 - 180)
            if error > 1 or abs(el - float(row["solar_noon_elevation_deg"])) > 0.5:
                print(
                    f"WARN: day {row['tmb_day']} legacy solar noon differs: corrected elevation={el:.2f}°, azimuth={az:.2f}° at stored time"
                )
        print("Legacy solar CSV retained unchanged; do not treat its windows as validated.")
        print(
            "GPX timestamps are not actual hiking times. Open horizon only; planning, not safety guarantees."
        )
        return 0 if all(checks.values()) else 1
    except (OSError, ValueError, KeyError, TypeError) as exc:
        print(f"ERROR: cannot validate dataset: {exc}")
        return 1


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