# exports/report_pdf.py
from __future__ import annotations
from pathlib import Path
from typing import Dict, Any, List, Optional
from datetime import datetime

from reportlab.lib.pagesizes import A4, landscape
from reportlab.lib import colors
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import mm
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, PageBreak

# ------------------------------------------------------------
# Öffentliche API
# ------------------------------------------------------------
def export_vergabe_pdf(
    out_path: Path | str,
    preisspiegel: Dict[str, Any],
    detail_rows: List[Dict[str, Any]],
    reasons: Optional[Dict[str, str]] = None,
    meta: Optional[Dict[str, Any]] = None,
    annotations: Optional[Dict[str, str]] = None,
) -> None:
    """
    Erzeugt einen kompakten Vergabeantrag als PDF (A4 quer).
    Erwartet:
      - preisspiegel: {"ranking":[(vendor,total),...], "summaries":[{vendor, brutto, rabatt_pct, ...}]}
      - detail_rows:  von core.price_compare.build_detailvergleich
      - reasons:      {pos: "KI-Notiz (DE)"} (optional)
      - meta:         {"bauvorhaben","projekt","lv","datum"} (optional)
      - annotations:  {pos: "Vendor1: note | Vendor2: note"} (optional)
    """
    out_path = Path(out_path)
    doc = SimpleDocTemplate(
        str(out_path),
        pagesize=landscape(A4),
        leftMargin=14 * mm,
        rightMargin=14 * mm,
        topMargin=12 * mm,
        bottomMargin=12 * mm,
        title="Vergabeantrag",
        author="Offert-Analyst",
    )

    styles = _styles()
    story = []

    # ---------------- Header
    story += _header_block(styles, meta)

    # ---------------- Preisspiegel (Summaries & Ranking)
    story.append(Paragraph("Preisspiegel – Zusammenfassung", styles["h2"]))
    story.append(Spacer(1, 4))
    t_sum = _table_preisspiegel(preisspiegel, styles)
    story.append(t_sum)
    story.append(Spacer(1, 10))

    # ---------------- Kurzer Detail-/Ausreißer-Block (kompakt)
    story.append(Paragraph("Detailvergleich – Auffälligkeiten (Auszug)", styles["h2"]))
    story.append(Spacer(1, 4))
    t_det = _table_detail_compact(detail_rows, reasons or {}, annotations or {}, styles, max_rows=40)
    story.append(t_det)

    # Footer/Stand
    story.append(Spacer(1, 8))
    now = datetime.now().strftime("%d.%m.%Y %H:%M")
    story.append(Paragraph(f"Erstellt: {now}", styles["small_right"]))

    doc.build(story)


# ------------------------------------------------------------
# Layout-Helfer
# ------------------------------------------------------------
def _styles():
    ss = getSampleStyleSheet()
    styles = {}

    styles["h1"] = ParagraphStyle(
        "h1",
        parent=ss["Heading1"],
        fontName="Helvetica-Bold",
        fontSize=18,
        leading=22,
        spaceAfter=6,
        textColor=colors.HexColor("#111111"),
    )
    styles["h2"] = ParagraphStyle(
        "h2",
        parent=ss["Heading2"],
        fontName="Helvetica-Bold",
        fontSize=13,
        leading=16,
        spaceAfter=4,
        textColor=colors.HexColor("#222222"),
    )
    styles["body"] = ParagraphStyle(
        "body",
        parent=ss["BodyText"],
        fontName="Helvetica",
        fontSize=9.5,
        leading=12,
        textColor=colors.black,
    )
    styles["small"] = ParagraphStyle(
        "small",
        parent=ss["BodyText"],
        fontName="Helvetica",
        fontSize=8.5,
        leading=11,
        textColor=colors.HexColor("#333333"),
    )
    styles["small_right"] = ParagraphStyle(
        "small_right",
        parent=ss["BodyText"],
        fontName="Helvetica",
        fontSize=8.5,
        leading=11,
        alignment=2,  # right
        textColor=colors.HexColor("#333333"),
    )
    styles["th"] = ParagraphStyle(
        "th",
        parent=ss["BodyText"],
        fontName="Helvetica-Bold",
        fontSize=9.3,
        leading=12,
        textColor=colors.HexColor("#111111"),
    )
    return styles


def _header_block(styles, meta: Optional[Dict[str, Any]]):
    meta = meta or {}
    bau = meta.get("bauvorhaben", "—")
    prj = meta.get("projekt", "—")
    lv  = meta.get("lv", "—")
    dat = meta.get("datum", "—")

    title = Paragraph("Vergabeantrag", styles["h1"])
    line1 = Paragraph(f"<b>Bauvorhaben:</b> {bau}", styles["body"])
    line2 = Paragraph(f"<b>Projekt:</b> {prj}", styles["body"])
    line3 = Paragraph(f"<b>Leistungsverzeichnis:</b> {lv} &nbsp;&nbsp; <b>Datum:</b> {dat}", styles["body"])

    spacer = Spacer(1, 6)
    return [title, spacer, line1, line2, line3, Spacer(1, 10)]


# ------------------------------------------------------------
# Tabellen
# ------------------------------------------------------------
def _table_preisspiegel(preisspiegel: Dict[str, Any], styles) -> Table:
    ranking = preisspiegel.get("ranking") or []
    summaries = preisspiegel.get("summaries") or []

    # Map für Rang
    rang_map = {vendor: idx + 1 for idx, (vendor, _total) in enumerate(ranking)}

    header = [
        Paragraph("Rang", styles["th"]),
        Paragraph("Anbieter", styles["th"]),
        Paragraph("Brutto [CHF]", styles["th"]),
        Paragraph("Rabatt [%]", styles["th"]),
        Paragraph("Skonto [%]", styles["th"]),
        Paragraph("Netto exkl. MwSt. [CHF]", styles["th"]),
        Paragraph("MwSt [%]", styles["th"]),
        Paragraph("Total inkl. MwSt. [CHF]", styles["th"]),
        Paragraph("Total (Fallback) [CHF]", styles["th"]),
    ]
    data = [header]

    if summaries:
        for s in summaries:
            vendor = s.get("vendor")
            row = [
                rang_map.get(vendor),
                vendor,
                _fmt_cur(s.get("brutto")),
                _fmt_pct(s.get("rabatt_pct")),
                _fmt_pct(s.get("skonto_pct")),
                _fmt_cur(s.get("netto_exkl_mwst")),
                _fmt_pct(s.get("mwst_pct")),
                _fmt_cur(s.get("total_inkl_mwst")),
                _fmt_cur(s.get("total")),
            ]
            data.append(row)
    else:
        # Fallback, wenn nur Ranking existiert
        for vendor, total in ranking:
            data.append([rang_map.get(vendor), vendor, "", "", "", "", "", "", _fmt_cur(total)])

    col_widths = [16*mm, 45*mm, 28*mm, 20*mm, 20*mm, 35*mm, 18*mm, 35*mm, 32*mm]

    t = Table(data, colWidths=col_widths, repeatRows=1)
    t.setStyle(TableStyle([
        ("FONT", (0,0), (-1,0), "Helvetica-Bold", 9.5),
        ("FONT", (0,1), (-1,-1), "Helvetica", 9.2),
        ("ALIGN", (0,0), (0,-1), "CENTER"),
        ("ALIGN", (2,1), (-1,-1), "RIGHT"),
        ("VALIGN", (0,0), (-1,-1), "MIDDLE"),
        ("GRID", (0,0), (-1,-1), 0.3, colors.HexColor("#b5b5b5")),
        ("BACKGROUND", (0,0), (-1,0), colors.HexColor("#efefef")),
        ("ROWBACKGROUNDS", (0,1), (-1,-1), [colors.white, colors.HexColor("#fafafa")]),
    ]))
    return t


def _table_detail_compact(
    detail_rows: List[Dict[str, Any]],
    reasons: Dict[str, str],
    annotations: Dict[str, str],
    styles,
    max_rows: int = 40
) -> Table:
    """
    Kompakte Tabelle für PDF (A4 quer lesbar):
    Spalten: Pos | Text | Menge | E. | Median (EP) | Min | Max | KI-Notiz | Anmerkungen
    """
    header = [
        Paragraph("Pos", styles["th"]),
        Paragraph("Text", styles["th"]),
        Paragraph("Menge", styles["th"]),
        Paragraph("E.", styles["th"]),
        Paragraph("Median EP", styles["th"]),
        Paragraph("Min (Anbieter)", styles["th"]),
        Paragraph("Max (Anbieter)", styles["th"]),
        Paragraph("KI-Notiz", styles["th"]),
        Paragraph("Anmerkungen", styles["th"]),
    ]
    data = [header]

    rows = detail_rows[:max_rows] if max_rows and len(detail_rows) > max_rows else detail_rows
    for r in rows:
        pos = str(r.get("Pos") or "")
        text = str(r.get("Text") or "")
        menge = r.get("Menge")
        einheit = r.get("Einheit") or ""
        median = r.get("Median")
        minv = r.get("Min Vendor") or ""
        maxv = r.get("Max Vendor") or ""
        note = reasons.get(pos) or ""
        ann = annotations.get(pos) or ""

        data.append([
            pos,
            text,
            _fmt_qty(menge),
            einheit,
            _fmt_cur(median),
            minv,
            maxv,
            note,
            ann,
        ])

    # Spaltenbreiten (A4 quer)
    col_widths = [16*mm, 78*mm, 18*mm, 12*mm, 22*mm, 32*mm, 32*mm, 50*mm, 60*mm]

    t = Table(data, colWidths=col_widths, repeatRows=1)
    t.setStyle(TableStyle([
        ("FONT", (0,0), (-1,0), "Helvetica-Bold", 9.3),
        ("FONT", (0,1), (-1,-1), "Helvetica", 9.0),
        ("ALIGN", (2,1), (2,-1), "RIGHT"),     # Menge
        ("ALIGN", (4,1), (4,-1), "RIGHT"),     # Median EP
        ("VALIGN", (0,0), (-1,-1), "TOP"),
        ("GRID", (0,0), (-1,-1), 0.3, colors.HexColor("#b5b5b5")),
        ("BACKGROUND", (0,0), (-1,0), colors.HexColor("#efefef")),
        ("ROWBACKGROUNDS", (0,1), (-1,-1), [colors.white, colors.HexColor("#fafafa")]),
    ]))
    return t


# ------------------------------------------------------------
# Formatierungs-Helfer
# ------------------------------------------------------------
def _fmt_cur(v) -> str:
    try:
        if v is None: return ""
        return f"{float(v):,.2f}".replace(",", "'")
    except Exception:
        return ""

def _fmt_qty(v) -> str:
    try:
        if v is None: return ""
        f = float(v)
        # 1/1000 Genauigkeit für Mengen
        if abs(f - round(f)) < 1e-9:
            return f"{int(round(f))}"
        return f"{f:,.3f}".replace(",", "'")
    except Exception:
        return ""

def _fmt_pct(v) -> str:
    try:
        if v is None: return ""
        return f"{float(v):.2f}"
    except Exception:
        return ""
