"""Build a combined chart of all direct mission TSI streams.

Reads existing per-mission daily CSV files from tsi_satellite_sources/,
overlays daily scatter + monthly mean line + annual mean marker for each
mission using that mission's established colour theme, and saves a single
composite PNG.

Scale note: data are plotted unadjusted on their native radiometric scales.
Pre-SORCE instruments (Nimbus-7, ACRIM I/SMM, ACRIM II/UARS, ACRIM III,
ERBS/ERBE) carry scale offsets of up to +12 W m^-2 relative to the modern
SI-traceable TIM scale adopted after Kopp & Lean (2011). No correction applied.
"""
from pathlib import Path
from typing import Any

import matplotlib.dates as mdates
import matplotlib.lines as mlines
import matplotlib.pyplot as plt
import pandas as pd


BASE_DIR = Path(__file__).parent
OUT_DIR = BASE_DIR / "tsi_satellite_sources"
OUT_PNG = OUT_DIR / "all_missions_combined_tsi.png"

# --------------------------------------------------------------------------
# Dataset registry – direct mission streams only (no composites / models).
# colors : (light, mid, dark) matching the per-mission individual panels.
# --------------------------------------------------------------------------
DATASETS: list[dict[str, Any]] = [
    {
        "label": "Nimbus-7 ERB Ch10C",
        "csv": OUT_DIR / "pre_sorce_individual_missions_daily.csv",
        "tsi_col": "tsi",
        "mission_filter": "NIMBUS-7 ERB Ch10C",
        "colors": ("#93c5fd", "#3b82f6", "#1d4ed8"),
        "scatter_alpha": 0.28,
        "scatter_s": 3,
    },
    {
        "label": "ACRIM I / SMM",
        "csv": OUT_DIR / "acrim_smm_tsi_daily.csv",
        "tsi_col": "tsi",
        "mission_filter": None,
        "colors": ("#fde68a", "#d97706", "#92400e"),
        "scatter_alpha": 0.40,
        "scatter_s": 5,
    },
    {
        "label": "ERBS / ERBE",
        "csv": OUT_DIR / "erbe_tsi_erbs_nat_orbital_observations.csv",
        "tsi_col": "tsi",
        "mission_filter": None,
        "colors": ("#f9a8d4", "#ec4899", "#9d174d"),
        "scatter_alpha": 0.28,
        "scatter_s": 4,
    },
    {
        "label": "ACRIM II / UARS",
        "csv": OUT_DIR / "acrim2_tsi_uars_nat_daily.csv",
        "tsi_col": "tsi",
        "mission_filter": None,
        "colors": ("#93c5fd", "#2563eb", "#1e3a8a"),
        "scatter_alpha": 0.28,
        "scatter_s": 5,
    },
    {
        "label": "SOHO / VIRGO V8",
        "csv": OUT_DIR / "soho_virgo_v8_tsi_daily.csv",
        "tsi_col": "tsi",
        "mission_filter": None,
        "colors": ("#67e8f9", "#0891b2", "#155e75"),
        "scatter_alpha": 0.25,
        "scatter_s": 3,
    },
    {
        "label": "ACRIM III / L2-DM",
        "csv": OUT_DIR / "acrim3_l2_daily_mean_daily.csv",
        "tsi_col": "tsi",
        "mission_filter": None,
        "colors": ("#a78bfa", "#7c3aed", "#4c1d95"),
        "scatter_alpha": 0.42,
        "scatter_s": 7,
    },
    {
        "label": "SORCE / TIM",
        "csv": OUT_DIR / "lisird_sorce_tsi_daily.csv",
        "tsi_col": "tsi",
        "mission_filter": None,
        "colors": ("#fdba74", "#f97316", "#c2410c"),
        "scatter_alpha": 0.20,
        "scatter_s": 3,
    },
    {
        "label": "PICARD / PREMOS",
        "csv": OUT_DIR / "picard_premos_tsi_daily.csv",
        "tsi_col": "tsi",
        "mission_filter": None,
        "colors": ("#22c55e", "#16a34a", "#14532d"),
        "scatter_alpha": 0.45,
        "scatter_s": 8,
    },
    {
        "label": "PICARD / SOVAP",
        "csv": OUT_DIR / "picard_sovap_tsi_daily.csv",
        "tsi_col": "tsi",
        "mission_filter": None,
        "colors": ("#fda4af", "#e11d48", "#881337"),
        "scatter_alpha": 0.50,
        "scatter_s": 8,
    },
    {
        "label": "TCTE / TIM",
        "csv": OUT_DIR / "versioned_tcte_tim_daily.csv",
        "tsi_col": "tsi",
        "mission_filter": None,
        "colors": ("#c4b5fd", "#8b5cf6", "#5b21b6"),
        "scatter_alpha": 0.25,
        "scatter_s": 3,
    },
    {
        "label": "CTIM",
        "csv": OUT_DIR / "lisird_ctim_tsi_daily.csv",
        "tsi_col": "tsi",
        "mission_filter": None,
        "colors": ("#4ade80", "#22c55e", "#15803d"),
        "scatter_alpha": 0.50,
        "scatter_s": 9,
    },
    {
        "label": "TSIS-1 / TIM",
        "csv": OUT_DIR / "versioned_tsis_tim_daily.csv",
        "tsi_col": "tsi",
        "mission_filter": None,
        "colors": ("#fca5a5", "#ef4444", "#991b1b"),
        "scatter_alpha": 0.38,
        "scatter_s": 3,
    },
]


def load_csv(path: Path, tsi_col: str, mission_filter: str | None) -> pd.DataFrame:
    """Load a per-mission daily CSV, floor any intraday timestamps to date,
    and average multiple same-day observations into a single daily mean."""
    df = pd.read_csv(path, parse_dates=["date"])
    if mission_filter is not None:
        df = df[df["mission"] == mission_filter].copy()
    # Floor datetime to calendar date (handles ERBS sub-daily timestamps)
    df["date"] = df["date"].dt.floor("D")
    if tsi_col != "tsi":
        df = df.rename(columns={tsi_col: "tsi"})
    df = df.groupby("date")["tsi"].mean().reset_index()
    df = df[(df["tsi"] > 0) & df["tsi"].notna()]
    return df.sort_values("date").reset_index(drop=True)


def build_chart() -> None:
    plt.style.use("seaborn-v0_8-whitegrid")
    fig, ax = plt.subplots(figsize=(16, 10), dpi=150)

    legend_handles = []

    for ds in DATASETS:
        frame = load_csv(ds["csv"], ds["tsi_col"], ds["mission_filter"])
        if frame.empty:
            print(f"  [WARN] {ds['label']}: no data loaded, skipping")
            continue

        monthly = frame.set_index("date").resample("MS").mean().reset_index()
        annual  = frame.set_index("date").resample("YS").mean().reset_index()
        annual["plot_date"] = annual["date"] + pd.offsets.Day(181)

        light, mid, dark = ds["colors"]

        ax.scatter(frame["date"], frame["tsi"],
                   s=ds["scatter_s"], color=light, alpha=ds["scatter_alpha"],
                   edgecolors="none", zorder=2)
        ax.plot(monthly["date"], monthly["tsi"],
                color=mid, linewidth=1.6, zorder=3)
        ax.plot(annual["plot_date"], annual["tsi"],
                color=dark, linewidth=2.0, marker="o", markersize=3.2, zorder=4)

        legend_handles.append(
            mlines.Line2D([], [], color=mid, linewidth=2.2, label=ds["label"])
        )
        print(f"  {ds['label']:22s}  "
              f"{frame['date'].min().date()} – {frame['date'].max().date()}  "
              f"rows={len(frame)}  "
              f"tsi={frame['tsi'].min():.2f}–{frame['tsi'].max():.2f}")

    ax.set_title(
        "All Direct Mission Streams — Total Solar Irradiance (Unadjusted Native Scales)",
        fontsize=15, pad=14,
    )
    ax.set_ylabel(r"Total Solar Irradiance (W m$^{-2}$)")
    ax.set_xlabel("Year")
    ax.xaxis.set_major_locator(mdates.YearLocator(5))
    ax.xaxis.set_major_formatter(mdates.DateFormatter("%Y"))

    ax.legend(handles=legend_handles, loc="upper right", frameon=True,
              fontsize=9.2, ncol=2)

    note = (
        "Data plotted on each instrument's native (unadjusted) radiometric scale.\n"
        r"Pre-SORCE instruments carry scale offsets of +3 to +12 W m$^{-2}$ above the modern SI-traceable TIM scale."
        "\n"
        "Light dots = daily values  \u2022  solid lines = monthly means  \u2022  dark circles = annual means"
    )
    ax.text(0.015, 0.03, note, transform=ax.transAxes, fontsize=8.8,
            bbox=dict(boxstyle="round,pad=0.40", facecolor="white",
                      edgecolor="#cbd5e1", alpha=0.96))

    fig.tight_layout()
    fig.savefig(OUT_PNG, bbox_inches="tight")
    plt.close(fig)
    print(f"\nSaved {OUT_PNG}")


def main() -> None:
    OUT_DIR.mkdir(parents=True, exist_ok=True)
    build_chart()


if __name__ == "__main__":
    main()
