"""PDF-Rechnungserstellung via ReportLab (Platypus). Standalone, kein Excel, kein LibreOffice."""

import os
import logging
from xml.sax.saxutils import escape as _esc

from core.models import _AV_KONSTANTEN, Mitglied
from core.utils import mask_filename_for_log

logger = logging.getLogger(__name__)


def render_invoice_pdf_html(
    system,
    mitglied: Mitglied,
    output_path: str = None,
) -> "str | None":
    """Rendert eine Rechnung direkt als PDF via ReportLab (Platypus).

    system: Abrechnungssystem-Instanz (liefert config, folder_rechnungen, _build_docx_context).
    Gibt den absoluten PDF-Pfad zurück oder None bei Fehler (fehlende Abhängigkeit oder Exception).
    """
    try:
        from reportlab.lib.pagesizes import A4
        from reportlab.lib.units import mm
        from reportlab.lib.colors import HexColor, white
        from reportlab.lib.enums import TA_RIGHT, TA_CENTER
        from reportlab.lib.styles import ParagraphStyle
        from reportlab.platypus import (
            SimpleDocTemplate, Table, TableStyle,
            Paragraph, Spacer, HRFlowable, Image,
        )
    except ImportError:
        logger.warning("reportlab nicht installiert – Fallback auf DOCX+LibreOffice.")
        return None

    # ── Kontext aus system._build_docx_context ────────────────────────────────
    ctx = system._build_docx_context(mitglied)
    has_bezug       = mitglied.Consumption > 0
    has_einspeisung = mitglied.Generation > 0

    accent_hex = "#" + str(
        system.config.get("Akzentfarbe", system.config.get("Accent_Color", "1B5E20"))
    ).strip().lstrip("#")
    try:
        ACCENT = HexColor(accent_hex)
    except Exception:
        ACCENT = HexColor("#1B5E20")

    abbuchung_modus = system.config.get(
        "Abbuchung_Modus", system.config.get("abbuchung_modus", "ueberweisung")
    ).strip().lower()
    is_av = abbuchung_modus == "abrechnungsverein"

    sepa_iban  = system.config.get("SEPA_IBAN",  system.config.get("sepa_iban",  ""))
    sepa_bic   = system.config.get("SEPA_BIC",   system.config.get("sepa_bic",   ""))
    creditor   = system.config.get("SEPA_Creditor_ID", system.config.get("sepa_creditor_id", ""))
    bank       = system.config.get("Bank",        system.config.get("bank",        ""))
    zvr_verein = str(system.config.get("ZVR", "")).strip()

    # Abrechnungsverein-Stammdaten (fest, nicht aus Config)
    av_name     = _AV_KONSTANTEN["name"]
    av_zvr      = _AV_KONSTANTEN["zvr"]
    av_iban     = _AV_KONSTANTEN["iban"]
    av_bic      = _AV_KONSTANTEN["bic"]
    av_creditor = _AV_KONSTANTEN["creditor_id"]
    av_adresse  = _AV_KONSTANTEN["adresse"]

    if output_path is None:
        output_path = os.path.join(
            system.folder_rechnungen,
            f"Rechnung_{mitglied.Rechnungsnummer}_{mitglied.Name4Rechnung}.pdf",
        )
    output_path = os.path.abspath(output_path)

    # ── Seite ─────────────────────────────────────────────────────────────────
    doc = SimpleDocTemplate(
        output_path, pagesize=A4,
        leftMargin=25*mm, rightMargin=18*mm,
        topMargin=18*mm, bottomMargin=22*mm,
        title=f"Rechnung {ctx['rechnungsnummer']}",
    )
    W = A4[0] - 43*mm   # nutzbare Breite

    # ── Styles ────────────────────────────────────────────────────────────────
    def S(name, **kw):
        defaults = dict(fontName="Helvetica", fontSize=9.5, leading=13)
        defaults.update(kw)
        return ParagraphStyle(name, **defaults)

    s_normal  = S("normal")
    s_small   = S("small",   fontSize=8,   leading=11, textColor=HexColor("#666666"))
    s_right   = S("right",   fontSize=9,   alignment=TA_RIGHT)
    s_lbl     = S("lbl",     fontSize=9,   textColor=HexColor("#666666"), alignment=TA_RIGHT)
    s_pay_lbl = S("pay_lbl", fontSize=8.5, textColor=HexColor("#666666"), leading=12)
    s_pay_val = S("pay_val", fontSize=8.5, leading=12)
    s_ust     = S("ust",     fontSize=8,   leading=11, textColor=HexColor("#555555"))
    s_footer  = S("footer",  fontSize=7.5, textColor=HexColor("#aaaaaa"), alignment=TA_CENTER)

    def P(text, style=None, bold=False):
        style = style or s_normal
        if bold:
            text = f"<b>{text}</b>"
        return Paragraph(text, style)

    GREY_BG  = HexColor("#f4f4f4")
    ROW_LINE = HexColor("#e8e8e8")

    story = []

    # ── Header: Logo links, Verein rechts ────────────────────────────────────
    logo_cell = ""
    for key in ("Logo_Path", "Logo_Filename"):
        lpath = system.config.get(key, "")
        if lpath and not os.path.isabs(lpath):
            lpath = os.path.join(system.main_path, "Config", lpath)
        if lpath and os.path.exists(lpath):
            try:
                logo_cell = Image(lpath, width=50*mm, height=18*mm, kind="proportional")
            except Exception:
                pass
            break

    _kleinunt_hdr   = str(system.config.get("Kleinunternehmer", "Ja")).strip().lower() == "ja"
    _verein_uid_hdr = system.config.get("UID_Nummer", "").strip()
    _verein_addr    = f"{_esc(ctx['vereinsstrasse'])}<br/>{_esc(ctx['vereinsort'])}"
    if not _kleinunt_hdr and _verein_uid_hdr:
        _verein_addr += f"<br/>UID-Nr.: {_esc(_verein_uid_hdr)}"
    verein_cell = [
        P(f"<b>{_esc(ctx['vereinsname'])}</b>",
          S("vn", fontName="Helvetica-Bold", fontSize=12,
            textColor=ACCENT, alignment=TA_RIGHT)),
        P(_verein_addr,
          S("va", fontSize=8, textColor=HexColor("#666666"),
            alignment=TA_RIGHT, leading=11)),
    ]

    hdr = Table([[logo_cell, verein_cell]], colWidths=[W * 0.5, W * 0.5])
    hdr.setStyle(TableStyle([
        ("VALIGN",        (0, 0), (-1, -1), "TOP"),
        ("BOTTOMPADDING", (0, 0), (-1, -1), 5 * mm),
        ("LINEBELOW",     (0, 0), (-1, -1), 0.5, HexColor("#cccccc")),
    ]))
    story += [hdr, Spacer(1, 6 * mm)]

    # ── Adressfenster links, Rechnungsmeta rechts ────────────────────────────
    _zvr_part = f" · ZVR: {_esc(zvr_verein)}" if zvr_verein else ""
    absender = P(
        f"<font size='7.5' color='#999999'>"
        f"{_esc(ctx['vereinsname'])} · {_esc(ctx['vereinsstrasse'])} · {_esc(ctx['vereinsort'])}{_zvr_part}"
        f"</font>",
    )
    recipient_cell = [
        absender,
        P(f"<b>{_esc(ctx['anschrift'])}</b>"),
        P(_esc(ctx["strasse"])),
        P(f"{_esc(ctx['plz'])} {_esc(ctx['ort'])}"),
    ]
    if ctx.get("mitglied_uid"):
        recipient_cell.append(P(f"UID-Nr.: {_esc(ctx['mitglied_uid'])}", s_small))

    is_gutschrift = ctx.get("is_gutschrift", False)
    faellig_lbl   = "Gutschriftsdatum:" if is_gutschrift else "Fälligkeitsdatum:"
    meta_rows = [
        [P("Rechnungsnummer:", s_lbl), P(f"<b>{_esc(ctx['rechnungsnummer'])}</b>", s_right)],
        [P("Rechnungsdatum:",  s_lbl), P(_esc(ctx["rechnungsdatum"]),  s_right)],
        [P(faellig_lbl, s_lbl),        P(_esc(ctx["faelligkeitsdatum"]), s_right)],
    ]
    meta_t = Table(meta_rows, colWidths=[42 * mm, 33 * mm])
    meta_t.setStyle(TableStyle([
        ("TOPPADDING",    (0, 0), (-1, -1), 1),
        ("BOTTOMPADDING", (0, 0), (-1, -1), 1),
        ("LEFTPADDING",   (0, 0), (-1, -1), 0),
    ]))

    addr_t = Table([[recipient_cell, meta_t]], colWidths=[W * 0.55, W * 0.45])
    addr_t.setStyle(TableStyle([("VALIGN", (0, 0), (-1, -1), "TOP")]))
    story += [addr_t, Spacer(1, 7 * mm)]

    # ── Titel + Anrede ────────────────────────────────────────────────────────
    story.append(P(ctx.get("doc_typ", "RECHNUNG"),
        S("title", fontName="Helvetica-Bold", fontSize=17,
          textColor=ACCENT, leading=22)))
    story.append(Spacer(1, 5 * mm))
    if is_gutschrift:
        intro_text = (
            f"{_esc(ctx['anrede'])} {_esc(ctx['name'])},<br/>"
            "wir schreiben Ihnen folgende Gutschrift aus der "
            "Energiegemeinschaft gut:"
        )
    else:
        intro_text = (
            f"{_esc(ctx['anrede'])} {_esc(ctx['name'])},<br/>"
            "wir verrechnen hiermit die Energieleistungen aus der "
            "Energiegemeinschaft:"
        )
    story.append(P(intro_text))
    story.append(Spacer(1, 5 * mm))

    # ── Positionstabelle ──────────────────────────────────────────────────────
    th   = S("th",   fontName="Helvetica", fontSize=8.5, leading=11, textColor=white)
    th_r = S("th_r", fontName="Helvetica", fontSize=8.5, leading=11,
             textColor=white, alignment=TA_RIGHT)
    td_r = S("td_r", fontSize=9, alignment=TA_RIGHT)

    rows = [[
        P("Beschreibung", th), P("Zeitraum", th),
        P("Menge (kWh)", th_r), P("Preis\n(ct/kWh)", th_r), P("Betrag (€)", th_r),
    ]]
    tstyles = [
        ("BACKGROUND",    (0, 0), (-1, 0), ACCENT),
        ("VALIGN",        (0, 0), (-1, 0), "MIDDLE"),
        ("TOPPADDING",    (0, 0), (-1, -1), 3),
        ("BOTTOMPADDING", (0, 0), (-1, -1), 3),
        ("LEFTPADDING",   (0, 0), (-1, -1), 5),
        ("RIGHTPADDING",  (0, 0), (-1, -1), 5),
    ]
    r = 1  # aktuelle Zeilennummer in der Tabelle

    def add_section(label):
        nonlocal r, tstyles
        rows.append([P(f"<b>{label}</b>", S("sec", fontSize=8.5)), "", "", "", ""])
        tstyles += [
            ("BACKGROUND", (0, r), (-1, r), GREY_BG),
            ("SPAN",       (0, r), (-1, r)),
        ]
        r += 1

    def add_item(desc, zeitraum, menge, preis, betrag):
        nonlocal r, tstyles
        rows.append([
            P(_esc(desc)), P(_esc(zeitraum)),
            P(_esc(menge), td_r), P(_esc(preis), td_r), P(_esc(betrag), td_r),
        ])
        tstyles.append(("LINEBELOW", (0, r), (-1, r), 0.3, ROW_LINE))
        r += 1

    if has_bezug:
        add_section(f"Strombezug · Zählpunkt …{ctx['zp_consumption']}")
        if ctx.get("bezug_netto_tarif"):
            # Regelbesteuerung: Netto-Zeile + MwSt 20%-Zeile
            add_item(
                "Bezug aus gemeinschaftlicher Erzeugungsanlage (Netto)",
                f"{ctx['consumption_von']} – {ctx['consumption_bis']}",
                ctx["consumption"], ctx["bezug_netto_tarif"], ctx["bezug_netto_betrag"],
            )
            add_item("Umsatzsteuer 20%", "", "", "", ctx["bezug_mwst_betrag"])
        else:
            add_item(
                "Bezug aus gemeinschaftlicher Erzeugungsanlage",
                f"{ctx['consumption_von']} – {ctx['consumption_bis']}",
                ctx["consumption"], ctx["tarif_bezug"], ctx["kosten_consumption"],
            )

    if has_einspeisung:
        add_section(f"Einspeisung · Zählpunkt …{ctx['zp_generation']}")
        if ctx.get("landwirt_netto_tarif"):
            # Landwirt (13%): Netto-Tarif, separater MwSt-Abzug
            add_item(
                "Einspeisung in gemeinschaftliche Erzeugungsanlage (Netto)",
                f"{ctx['generation_von']} – {ctx['generation_bis']}",
                ctx["generation"],
                ctx["landwirt_netto_tarif"],
                f"-{ctx['landwirt_netto_betrag']}",
            )
            add_item("Umsatzsteuer 13%", "", "", "", f"-{ctx['landwirt_mwst_betrag']}")
        else:
            add_item(
                "Einspeisung in gemeinschaftliche Erzeugungsanlage",
                f"{ctx['generation_von']} – {ctx['generation_bis']}",
                ctx["generation"], ctx["tarif_einspeisung"], ctx["kosten_generation"],
            )
            # RC-Abzugszeile: Unternehmer 20% + Mitglied trägt
            if ctx.get("rc_mwst_betrag"):
                add_item("RC-Anteil", "", "", "", ctx["rc_mwst_betrag"])

    # Summenzeile
    rows.append([
        P("<b>Gesamtbetrag</b>", S("tot", fontSize=10.5, fontName="Helvetica-Bold")),
        "", "", "",
        P(f"<b>{_esc(ctx['gesamtkosten'])} €</b>",
          S("tot_r", fontSize=10.5, fontName="Helvetica-Bold",
            textColor=ACCENT, alignment=TA_RIGHT)),
    ])
    tstyles += [
        ("SPAN",          (0, r), (-2, r)),
        ("LINEABOVE",     (0, r), (-1, r), 1,   HexColor("#bbbbbb")),
        ("LINEBELOW",     (0, r), (-1, r), 2,   ACCENT),
        ("TOPPADDING",    (0, r), (-1, r), 5),
        ("BOTTOMPADDING", (0, r), (-1, r), 5),
    ]

    col_w = [W * f for f in (0.37, 0.22, 0.13, 0.13, 0.15)]
    items_t = Table(rows, colWidths=col_w)
    items_t.setStyle(TableStyle(tstyles))
    story += [items_t, Spacer(1, 3 * mm)]

    # ── USt-Hinweise ──────────────────────────────────────────────────────────
    for hint_key, label in (
        ("ust_hint_bezug", "Bezug"),
        ("ust_hint_einspeisung", "Einspeisung"),
    ):
        hint = ctx.get(hint_key, "")
        if hint:
            story.append(P(f"{label}: {_esc(hint)}", s_ust))
    story.append(Spacer(1, 4 * mm))

    # ── Zahlungsinformation ───────────────────────────────────────────────────
    # Block nur für AV und eigenes_konto (Überweisung: kein automatischer Zahlungsblock)
    _show_payment_block = abbuchung_modus in ("abrechnungsverein", "eigenes_konto")
    if _show_payment_block:
        story.append(P("Zahlungsinformation",
            S("pay_title", fontName="Helvetica-Bold", fontSize=9.5, textColor=ACCENT)))
        story.append(Spacer(1, 2 * mm))

    pay_rows = []
    if is_av and _show_payment_block:
        av_iban_bic = _esc(av_iban) + (f" · BIC: {_esc(av_bic)}" if av_bic else "")
        _action = "Gutschrift durch:" if is_gutschrift else "Abbuchung durch:"
        _durchf = "Überweisung auf Ihr Konto" if is_gutschrift else "SEPA-Lastschrift"
        pay_rows = [
            (_action,
             f"<b>{_esc(av_name)}</b> im Auftrag von {_esc(ctx['vereinsname'])}"),
            ("ZVR-Zahl:",               _esc(av_zvr)),
            ("Adresse:",                _esc(av_adresse)),
            ("Konto Abrechnungsverein:", av_iban_bic),
            ("Gläubiger-ID:",           _esc(av_creditor)),
            ("Ihr Konto (IBAN):",       _esc(ctx["kontonummer"])),
            ("Durchführung am:",
             f"{_esc(ctx['faelligkeitsdatum'])} ({_durchf})"),
        ]
    elif _show_payment_block:
        iban_bic   = _esc(sepa_iban) + (f" · BIC: {_esc(sepa_bic)}" if sepa_bic else "")
        vereinsadr = ", ".join(filter(None, [
            system.config.get("Vereinsstrasse", "").strip(),
            system.config.get("Vereinsort",     "").strip(),
        ]))
        _action = "Gutschrift durch:" if is_gutschrift else "Abbuchung durch:"
        _durchf = "Überweisung auf Ihr Konto" if is_gutschrift else "SEPA-Lastschrift"
        pay_rows = [
            (_action,              f"<b>{_esc(ctx['vereinsname'])}</b>"),
            ("ZVR-Zahl:",          _esc(zvr_verein)),
            ("Adresse:",           _esc(vereinsadr)),
            ("Vereinskonto (IBAN):", iban_bic),
            ("Gläubiger-ID:",      _esc(creditor)),
            ("Ihr Konto (IBAN):",  _esc(ctx["kontonummer"])),
            ("Durchführung am:",
             f"{_esc(ctx['faelligkeitsdatum'])} ({_durchf})"),
        ]

    if _show_payment_block and pay_rows:
        pay_data = [[P(lbl, s_pay_lbl), P(val, s_pay_val)] for lbl, val in pay_rows]
        pay_t = Table(pay_data, colWidths=[42 * mm, W - 42 * mm])
        pay_t.setStyle(TableStyle([
            ("BACKGROUND",    (0, 0), (-1, -1), HexColor("#f7f7f7")),
            ("BOX",           (0, 0), (-1, -1), 0.5, HexColor("#dddddd")),
            ("TOPPADDING",    (0, 0), (-1, -1), 2),
            ("BOTTOMPADDING", (0, 0), (-1, -1), 2),
            ("LEFTPADDING",   (0, 0), (-1, -1), 5),
            ("RIGHTPADDING",  (0, 0), (-1, -1), 5),
            ("VALIGN",        (0, 0), (-1, -1), "TOP"),
        ]))
        story.append(pay_t)

    # ── Footer (Canvas-Callback: immer am unteren Seitenrand) ────────────────
    _footer_text = (
        f"{ctx['vereinsname']} · "
        f"{ctx['vereinsstrasse']} · "
        f"{ctx['vereinsort']}"
        + (f" · ZVR: {zvr_verein}" if zvr_verein else "")
    )
    _page_w, _page_h = A4
    _left_m, _right_m = 25 * mm, 18 * mm
    _footer_y = 12 * mm

    def _draw_footer(canvas, doc):
        canvas.saveState()
        canvas.setStrokeColor(HexColor("#dddddd"))
        canvas.setLineWidth(0.3)
        _line_y = _footer_y + 4 * mm
        canvas.line(_left_m, _line_y, _page_w - _right_m, _line_y)
        canvas.setFont("Helvetica", 7.5)
        canvas.setFillColor(HexColor("#aaaaaa"))
        canvas.drawCentredString(_page_w / 2, _footer_y, _footer_text)
        canvas.restoreState()

    # ── PDF schreiben ─────────────────────────────────────────────────────────
    try:
        doc.build(story, onFirstPage=_draw_footer, onLaterPages=_draw_footer)
        if os.path.exists(output_path):
            logger.info(f"PDF (ReportLab): {mask_filename_for_log(output_path)}")
            return output_path
        logger.warning("ReportLab: PDF nach build() nicht vorhanden.")
    except Exception as e:
        logger.warning(f"ReportLab PDF-Erstellung fehlgeschlagen: {e}")

    return None
