"""PDF report generation for fleet screening results.

Uses fpdf2 to produce a professional conjunction assessment report
with cover page, summary, table, plots, and CDM excerpts.
"""

from __future__ import annotations

import logging
import tempfile
from datetime import UTC, datetime
from pathlib import Path

import numpy as np
from fpdf import FPDF

from satguard.cdm.writer import write_cdm
from satguard.fleet.batch import ScoredConjunction
from satguard.fleet.parser import FleetConfig

logger = logging.getLogger("satguard.report")

# Colors (RGB)
_DARK_BLUE = (15, 30, 75)
_MEDIUM_BLUE = (40, 80, 150)
_LIGHT_GRAY = (240, 240, 240)
_WHITE = (255, 255, 255)
_RED = (200, 50, 50)
_BLACK = (0, 0, 0)


def generate_report(
    fleet: FleetConfig,
    conjunctions: list[ScoredConjunction],
    output: Path,
    generation_time: datetime | None = None,
) -> Path:
    """Generate a PDF report for fleet screening results.

    Sections:
        1. Cover page with fleet name and summary stats
        2. Executive summary
        3. Conjunction table (sorted by Pc desc)
        4. Pc distribution histogram
        5. Miss distance vs TCA scatter
        6. Top 3 CDM excerpts
        7. Footer on every page

    Args:
        fleet: Fleet configuration used for screening.
        conjunctions: Scored conjunction results (sorted by Pc desc).
        output: Output PDF file path.
        generation_time: Override generation timestamp (default: now UTC).

    Returns:
        Path to the generated PDF file.
    """
    if generation_time is None:
        generation_time = datetime.now(UTC)

    pdf = _SatGuardPDF(fleet, generation_time)
    pdf.set_auto_page_break(auto=True, margin=20)

    # 1. Cover page
    _add_cover(pdf, fleet, conjunctions, generation_time)

    # 2. Executive summary
    _add_executive_summary(pdf, fleet, conjunctions, generation_time)

    # 3. Conjunction table
    _add_conjunction_table(pdf, conjunctions)

    # 4. Plots (Pc histogram + miss distance scatter)
    _add_plots(pdf, conjunctions)

    # 5. CDM excerpts (top 3)
    _add_cdm_excerpts(pdf, conjunctions)

    # Save
    output.parent.mkdir(parents=True, exist_ok=True)
    pdf.output(str(output))
    logger.info("Report saved: %s", output)
    return output


class _SatGuardPDF(FPDF):
    """FPDF subclass with SatGuard header/footer."""

    def __init__(self, fleet: FleetConfig, gen_time: datetime) -> None:
        super().__init__(orientation="P", unit="mm", format="A4")
        self._fleet_name = fleet.name
        self._gen_time = gen_time
        self._is_cover = True

    def header(self) -> None:
        if self._is_cover:
            return
        self.set_font("Helvetica", "B", 9)
        self.set_text_color(*_MEDIUM_BLUE)
        self.cell(0, 8, f"SatGuard Fleet Report - {self._fleet_name}", align="L")
        self.ln(10)
        self.set_draw_color(*_MEDIUM_BLUE)
        self.line(10, self.get_y(), 200, self.get_y())
        self.ln(3)

    def footer(self) -> None:
        self.set_y(-15)
        self.set_font("Helvetica", "I", 7)
        self.set_text_color(128, 128, 128)
        ts = self._gen_time.strftime("%Y-%m-%d %H:%M UTC")
        self.cell(0, 10, f"Generated by SatGuard v0.5 - {ts}", align="L")
        self.cell(0, 10, f"Page {self.page_no()}/{{nb}}", align="R")


def _add_cover(
    pdf: _SatGuardPDF,
    fleet: FleetConfig,
    conjunctions: list[ScoredConjunction],
    gen_time: datetime,
) -> None:
    """Add cover page."""
    pdf.add_page()
    pdf.alias_nb_pages()

    # Background band
    pdf.set_fill_color(*_DARK_BLUE)
    pdf.rect(0, 0, 210, 120, "F")

    # Title
    pdf.set_y(35)
    pdf.set_font("Helvetica", "B", 28)
    pdf.set_text_color(*_WHITE)
    pdf.cell(0, 15, "SatGuard", align="C")
    pdf.ln(18)

    pdf.set_font("Helvetica", "", 16)
    pdf.cell(0, 10, "Fleet Conjunction Assessment Report", align="C")
    pdf.ln(20)

    pdf.set_font("Helvetica", "B", 20)
    pdf.cell(0, 12, fleet.name, align="C")
    pdf.ln(20)

    pdf.set_font("Helvetica", "", 11)
    pdf.cell(0, 8, gen_time.strftime("%Y-%m-%d %H:%M UTC"), align="C")

    # Stats block below the blue band
    pdf.set_y(135)
    pdf.set_text_color(*_BLACK)
    pdf.set_font("Helvetica", "", 12)

    stats = [
        ("Fleet Objects", str(len(fleet.objects))),
        ("Screening Window", f"{fleet.thresholds.days} days"),
        ("Miss Threshold", f"{fleet.thresholds.miss_km:.0f} km"),
        ("Pc Threshold", f"{fleet.thresholds.pc:.1e}"),
        ("Conjunctions Found", str(len(conjunctions))),
    ]

    for label, value in stats:
        pdf.set_font("Helvetica", "", 11)
        pdf.cell(90, 9, f"  {label}:", align="R")
        pdf.set_font("Helvetica", "B", 11)
        pdf.cell(90, 9, f"  {value}", align="L")
        pdf.ln(9)

    pdf._is_cover = False


def _add_executive_summary(
    pdf: _SatGuardPDF,
    fleet: FleetConfig,
    conjunctions: list[ScoredConjunction],
    gen_time: datetime,
) -> None:
    """Add executive summary page."""
    pdf.add_page()

    pdf.set_font("Helvetica", "B", 16)
    pdf.set_text_color(*_DARK_BLUE)
    pdf.cell(0, 12, "Executive Summary", align="L")
    pdf.ln(15)

    pdf.set_text_color(*_BLACK)
    pdf.set_font("Helvetica", "", 10)

    if not conjunctions:
        pdf.multi_cell(0, 6, "No conjunctions above the configured thresholds were found "
                       "during the screening window. All fleet objects are clear.")
        return

    max_pc = max(c.pc for c in conjunctions)
    min_miss = min(c.event.miss_distance_km for c in conjunctions)
    max_vrel = max(c.event.relative_velocity_km_s for c in conjunctions)

    # High-risk count
    high_risk = sum(1 for c in conjunctions if c.pc >= 1e-4)
    medium_risk = sum(1 for c in conjunctions if 1e-6 <= c.pc < 1e-4)

    summary_lines = [
        f"Total conjunctions: {len(conjunctions)}",
        f"High risk (Pc >= 1e-4): {high_risk}",
        f"Medium risk (1e-6 <= Pc < 1e-4): {medium_risk}",
        "",
        f"Maximum Pc: {max_pc:.2e}",
        f"Closest approach: {min_miss:.3f} km ({min_miss * 1000:.0f} m)",
        f"Maximum relative velocity: {max_vrel:.2f} km/s",
        "",
        f"Fleet: {fleet.name} ({len(fleet.objects)} objects)",
        f"Window: {fleet.thresholds.days} days from TLE epoch",
        f"Report generated: {gen_time.strftime('%Y-%m-%d %H:%M UTC')}",
    ]

    for line in summary_lines:
        pdf.cell(0, 6, f"  {line}", align="L")
        pdf.ln(6)

    # Risk assessment box
    pdf.ln(8)
    if high_risk > 0:
        pdf.set_fill_color(255, 220, 220)
        pdf.set_font("Helvetica", "B", 11)
        pdf.cell(0, 10, f"  WARNING: {high_risk} HIGH-RISK conjunction(s) detected", fill=True)
    elif medium_risk > 0:
        pdf.set_fill_color(255, 245, 210)
        pdf.set_font("Helvetica", "B", 11)
        pdf.cell(0, 10, f"  NOTICE: {medium_risk} medium-risk conjunction(s) detected", fill=True)
    else:
        pdf.set_fill_color(220, 255, 220)
        pdf.set_font("Helvetica", "B", 11)
        pdf.cell(0, 10, "  ALL CLEAR: All conjunctions are low risk", fill=True)


def _add_conjunction_table(
    pdf: _SatGuardPDF,
    conjunctions: list[ScoredConjunction],
) -> None:
    """Add conjunction table sorted by Pc desc."""
    pdf.add_page()

    pdf.set_font("Helvetica", "B", 16)
    pdf.set_text_color(*_DARK_BLUE)
    pdf.cell(0, 12, "Conjunction Details", align="L")
    pdf.ln(15)

    if not conjunctions:
        pdf.set_font("Helvetica", "", 10)
        pdf.set_text_color(*_BLACK)
        pdf.cell(0, 8, "No conjunctions to report.")
        return

    # Table header
    col_widths = [12, 25, 25, 42, 22, 22, 30]
    headers = ["#", "Primary", "Secondary", "TCA (UTC)", "Miss (km)", "Vrel (km/s)", "Pc"]

    pdf.set_font("Helvetica", "B", 8)
    pdf.set_fill_color(*_DARK_BLUE)
    pdf.set_text_color(*_WHITE)

    for w, h_text in zip(col_widths, headers, strict=True):
        pdf.cell(w, 7, h_text, border=1, align="C", fill=True)
    pdf.ln(7)

    # Table rows
    pdf.set_text_color(*_BLACK)
    pdf.set_font("Helvetica", "", 7)

    for i, sc in enumerate(conjunctions[:50]):  # Max 50 rows
        e = sc.event
        fill = i % 2 == 0
        if fill:
            pdf.set_fill_color(*_LIGHT_GRAY)

        # Color-code Pc
        if sc.pc >= 1e-4:
            pc_color = _RED
        elif sc.pc >= 1e-6:
            pc_color = (180, 120, 0)
        else:
            pc_color = (0, 120, 0)

        row_data = [
            str(i + 1),
            str(e.norad_id_primary),
            str(e.norad_id_secondary),
            e.tca.strftime("%Y-%m-%d %H:%M:%S"),
            f"{e.miss_distance_km:.3f}",
            f"{e.relative_velocity_km_s:.2f}",
        ]

        for w, text in zip(col_widths[:-1], row_data, strict=True):
            pdf.cell(w, 6, text, border=1, align="C", fill=fill)

        # Pc cell with color
        pdf.set_text_color(*pc_color)
        pdf.set_font("Helvetica", "B", 7)
        pdf.cell(col_widths[-1], 6, f"{sc.pc:.2e}", border=1, align="C", fill=fill)
        pdf.set_text_color(*_BLACK)
        pdf.set_font("Helvetica", "", 7)
        pdf.ln(6)

        # Page break if needed
        if pdf.get_y() > 265:
            pdf.add_page()
            pdf.set_font("Helvetica", "B", 8)
            pdf.set_fill_color(*_DARK_BLUE)
            pdf.set_text_color(*_WHITE)
            for w, h_text in zip(col_widths, headers, strict=True):
                pdf.cell(w, 7, h_text, border=1, align="C", fill=True)
            pdf.ln(7)
            pdf.set_text_color(*_BLACK)
            pdf.set_font("Helvetica", "", 7)


def _add_plots(
    pdf: _SatGuardPDF,
    conjunctions: list[ScoredConjunction],
) -> None:
    """Add Pc histogram and miss distance scatter plot."""
    if not conjunctions:
        return

    import matplotlib
    matplotlib.use("Agg")
    import matplotlib.pyplot as plt

    pdf.add_page()
    pdf.set_font("Helvetica", "B", 16)
    pdf.set_text_color(*_DARK_BLUE)
    pdf.cell(0, 12, "Statistical Analysis", align="L")
    pdf.ln(15)

    pcs = [c.pc for c in conjunctions if c.pc > 0]
    miss_dists = [c.event.miss_distance_km for c in conjunctions]
    tcas = [c.event.tca for c in conjunctions]

    # Plot 1: Pc distribution histogram
    if pcs:
        fig1, ax1 = plt.subplots(figsize=(7, 3.5))
        log_pcs = [np.log10(p) for p in pcs]
        ax1.hist(log_pcs, bins=20, color="#2850AA", edgecolor="white", alpha=0.85)
        ax1.set_xlabel("log10(Pc)")
        ax1.set_ylabel("Count")
        ax1.set_title("Collision Probability Distribution")
        ax1.grid(True, alpha=0.3)
        fig1.tight_layout()

        with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as f:
            fig1.savefig(f.name, dpi=150, bbox_inches="tight")
            plt.close(fig1)
            pdf.image(f.name, x=15, w=180)

    pdf.ln(5)

    # Plot 2: Miss distance vs TCA scatter
    if tcas and miss_dists:
        import matplotlib.dates as mdates

        fig2, ax2 = plt.subplots(figsize=(7, 3.5))
        colors = ["#c83232" if c.pc >= 1e-4 else "#b47800" if c.pc >= 1e-6 else "#007830"
                  for c in conjunctions]
        tca_nums = mdates.date2num(tcas)
        ax2.scatter(
            tca_nums, miss_dists, c=colors, s=30, alpha=0.7,
            edgecolors="white", linewidths=0.5,
        )
        ax2.xaxis.set_major_formatter(mdates.DateFormatter("%Y-%m-%d %H:%M"))
        ax2.set_xlabel("TCA (UTC)")
        ax2.set_ylabel("Miss Distance (km)")
        ax2.set_title("Miss Distance vs Time of Closest Approach")
        ax2.grid(True, alpha=0.3)
        fig2.autofmt_xdate()
        fig2.tight_layout()

        with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as f:
            fig2.savefig(f.name, dpi=150, bbox_inches="tight")
            plt.close(fig2)
            # Check if we need a new page
            if pdf.get_y() > 170:
                pdf.add_page()
            pdf.image(f.name, x=15, w=180)


def _add_cdm_excerpts(
    pdf: _SatGuardPDF,
    conjunctions: list[ScoredConjunction],
) -> None:
    """Add CDM excerpts for top 3 conjunctions."""
    top = conjunctions[:3]
    if not top:
        return

    pdf.add_page()
    pdf.set_font("Helvetica", "B", 16)
    pdf.set_text_color(*_DARK_BLUE)
    pdf.cell(0, 12, "CDM Excerpts (Top 3)", align="L")
    pdf.ln(15)

    for i, sc in enumerate(top):
        cdm_text = write_cdm(sc.event, sc.pc)

        pdf.set_font("Helvetica", "B", 10)
        pdf.set_text_color(*_MEDIUM_BLUE)
        pdf.cell(0, 8, f"Conjunction #{i + 1}: NORAD {sc.event.norad_id_primary} "
                 f"vs {sc.event.norad_id_secondary} (Pc={sc.pc:.2e})")
        pdf.ln(9)

        pdf.set_font("Courier", "", 7)
        pdf.set_text_color(*_BLACK)
        pdf.set_fill_color(*_LIGHT_GRAY)

        for line in cdm_text.strip().split("\n"):
            if pdf.get_y() > 265:
                pdf.add_page()
            pdf.cell(0, 4, f"  {line}", fill=True)
            pdf.ln(4)

        pdf.ln(6)
