"""Génération PDF pour facture extraite – présentation type FACTURE DE VENTE (modèle RDC)."""
from io import BytesIO
from decimal import Decimal

from reportlab.lib import colors
from reportlab.lib.pagesizes import A4
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import mm
from reportlab.pdfgen import canvas as pdf_canvas
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle
from reportlab.graphics import renderPDF

from reportlab.graphics.barcode.qr import QrCodeWidget
from reportlab.graphics.shapes import Drawing


def _qr_flowable(qr_raw: str, size_mm: float = 25) -> Drawing:
    """
    Génère un QR code (Drawing) via ReportLab sans dépendances externes.

    IMPORTANT :
    - QrCodeWidget n'a pas de .scale() sur certaines versions
    - donc on applique la transformation sur le Drawing (transform matrix)
    - et on translate pour remettre l'origine visible (bounds[0], bounds[1])
    """
    size = float(size_mm) * mm
    widget = QrCodeWidget(qr_raw)

    # bounds = (x1, y1, x2, y2)
    x1, y1, x2, y2 = widget.getBounds()
    w = x2 - x1
    h = y2 - y1

    # fallback minimal si bounds bizarres
    if w <= 0 or h <= 0:
        d = Drawing(size, size)
        d.add(widget)
        return d

    # scale pour faire tenir le QR dans un carré size x size
    sx = size / w
    sy = size / h

    # transform = [a, b, c, d, e, f] équivaut à :
    # x' = a*x + c*y + e
    # y' = b*x + d*y + f
    # Ici : scale + translation pour ramener x1,y1 à 0,0
    d = Drawing(size, size, transform=[sx, 0, 0, sy, -x1 * sx, -y1 * sy])
    d.add(widget)
    return d


def make_qr_overlay_pdf(qr_raw: str, size_mm: float = 22, x_mm: float = 10, y_mm: float = 100) -> BytesIO:
    """
    Crée un PDF d'une page A4 contenant uniquement le QR à la position (x_mm, y_mm) depuis le bas-gauche.
    Utilisé pour superposer le QR sur un PDF xhtml2pdf (sans fond, seul le QR est dessiné).
    """
    buf = BytesIO()
    c = pdf_canvas.Canvas(buf, pagesize=A4)
    w_page, h_page = A4
    # Position en points : origine en bas à gauche
    x_pt = x_mm * mm
    y_pt = y_mm * mm
    qr_drawing = _qr_flowable(qr_raw, size_mm=size_mm)
    renderPDF.draw(qr_drawing, c, x_pt, y_pt)
    c.showPage()
    c.save()
    buf.seek(0)
    return buf


def _fmt_cdf(value):
    """Format nombre style CDF : 10.000,00 (point = milliers, virgule = décimales)."""
    if value is None:
        return "—"
    if isinstance(value, Decimal):
        value = float(value)
    s = f"{value:,.2f}"
    parts = s.split(".")
    integer = parts[0].replace(",", ".")
    decimal = parts[1]
    return f"{integer},{decimal}"


def render_extracted_invoice_pdf(normalized_invoice):
    inv = normalized_invoice
    soc = inv.societe

    buffer = BytesIO()
    doc = SimpleDocTemplate(
        buffer,
        pagesize=A4,
        rightMargin=15 * mm,
        leftMargin=15 * mm,
        topMargin=15 * mm,
        bottomMargin=15 * mm,
    )
    styles = getSampleStyleSheet()
    title_style = ParagraphStyle(
        name="InvoiceTitle",
        parent=styles["Normal"],
        fontSize=14,
        alignment=1,
        spaceAfter=4,
    )
    story = []

    # ----- En-tête société -----
    company_lines = []
    if soc:
        company_lines.append((soc.nom or "").upper() or "—")
        if getattr(soc, "point_de_vente", None):
            company_lines.append(f"Point de vente : {soc.point_de_vente}")
        if soc.nif:
            company_lines.append(f"NIF : {soc.nif}")
        if soc.adresse:
            for line in soc.adresse.strip().split("\n"):
                if line.strip():
                    company_lines.append(line.strip())
        if getattr(soc, "telephone", None):
            company_lines.append(str(soc.telephone))
        if getattr(soc, "email", None):
            company_lines.append(str(soc.email))
    else:
        company_lines.append("—")

    client_label_style = ParagraphStyle(
        name="CB",
        fontSize=10,
        textColor=colors.white,
        backColor=colors.HexColor("#505050"),
        alignment=2,
    )

    client_type = getattr(inv, "client_type", "") or "—"
    header_left = "\n".join(company_lines)
    header_right_body = (
        f"Type : {client_type}<br/>"
        f"Nom : {inv.client_nom or '—'}<br/>"
        f"NIF : {inv.client_nif or '—'}<br/>"
        f"Adresse : {(inv.client_adresse or '—')}<br/>"
        f"Contact : {inv.client_telephone or '—'}"
    )

    header_final_data = [
        [
            Paragraph(header_left.replace("\n", "<br/>"), styles["Normal"]),
            Paragraph("<b>CLIENT</b>", client_label_style),
        ],
        [
            "",
            Paragraph(header_right_body, styles["Normal"]),
        ],
    ]
    t_head = Table(header_final_data, colWidths=[95 * mm, 90 * mm])
    t_head.setStyle(TableStyle([
        ("ALIGN", (0, 0), (0, -1), "LEFT"),
        ("ALIGN", (1, 0), (1, -1), "RIGHT"),
        ("VALIGN", (0, 0), (-1, -1), "TOP"),
        ("FONTSIZE", (0, 0), (-1, -1), 9),
        ("BACKGROUND", (1, 0), (1, 0), colors.HexColor("#505050")),
        ("TEXTCOLOR", (1, 0), (1, 0), colors.white),
        ("BOX", (0, 0), (-1, -1), 0.5, colors.grey),
        ("INNERGRID", (0, 0), (-1, -1), 0.25, colors.lightgrey),
    ]))
    story.append(t_head)
    story.append(Spacer(1, 8 * mm))

    # ----- Titre -----
    story.append(Paragraph((inv.invoice_type or "FACTURE DE VENTE").upper(), title_style))
    inv_no = inv.invoice_number or str(inv.id)
    story.append(Paragraph(
        f"Facture n° {inv_no}",
        ParagraphStyle(name="InvNum", parent=styles["Normal"], fontSize=12, alignment=1, spaceAfter=8)
    ))
    story.append(Spacer(1, 4 * mm))

    # ----- Tableau lignes -----
    col_widths = [8 * mm, 60 * mm, 35 * mm, 22 * mm, 37 * mm]
    data = [["#", "Désignation", "Prix unitaire (TTC)", "Quantité", "Montant (TTC)"]]
    for i, line in enumerate(inv.lines.all(), 1):
        data.append([
            str(i),
            (line.designation or "—")[:60],
            _fmt_cdf(line.unit_price_ttc),
            _fmt_cdf(line.quantity) if line.quantity is not None else "—",
            _fmt_cdf(line.amount_ttc),
        ])
    t_lines = Table(data, colWidths=col_widths)
    t_lines.setStyle(TableStyle([
        ("BACKGROUND", (0, 0), (-1, 0), colors.HexColor("#E8E8E8")),
        ("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"),
        ("FONTSIZE", (0, 0), (-1, -1), 9),
        ("ALIGN", (0, 0), (0, -1), "CENTER"),
        ("ALIGN", (2, 0), (-1, -1), "RIGHT"),
        ("ALIGN", (1, 0), (1, -1), "LEFT"),
        ("GRID", (0, 0), (-1, -1), 0.5, colors.grey),
        ("TOPPADDING", (0, 0), (-1, -1), 3),
        ("BOTTOMPADDING", (0, 0), (-1, -1), 3),
    ]))
    story.append(t_lines)
    story.append(Spacer(1, 8 * mm))

    # ----- Récap -----
    recap_left = [
        f"Nombre d'articles : {inv.nb_articles or '—'}",
        f"Mode de paiement : {inv.payment_mode or '—'}",
    ]
    recap_right = [
        f"H.T. [B] Taxable 16,00% : {_fmt_cdf(inv.ht_taxable_16)}",
        f"TVA [B] Taxable 16,00% : {_fmt_cdf(inv.tva_16)}",
        f"TOTAL TVA : {_fmt_cdf(inv.tva_16)}",
        "",
        f"Total TTC : CDF {_fmt_cdf(inv.total_ttc_cdf)}",
    ]
    if inv.total_ttc_usd is not None:
        recap_right.append(f"Montant TTC : USD {_fmt_cdf(inv.total_ttc_usd)}")
    if inv.exchange_rate is not None and inv.exchange_rate_date:
        recap_right.append(f"Cours de change {_fmt_cdf(inv.exchange_rate)} du {inv.exchange_rate_date}")

    recap_data = [[
        Paragraph("<br/>".join(recap_left), styles["Normal"]),
        Paragraph("<br/>".join(recap_right), ParagraphStyle(name="RecapR", alignment=2, fontSize=9)),
    ]]
    t_recap = Table(recap_data, colWidths=[95 * mm, 90 * mm])
    t_recap.setStyle(TableStyle([
        ("ALIGN", (0, 0), (0, -1), "LEFT"),
        ("ALIGN", (1, 0), (1, -1), "RIGHT"),
        ("FONTSIZE", (0, 0), (-1, -1), 9),
        ("FONTNAME", (0, 0), (1, 0), "Helvetica-Bold"),
    ]))
    story.append(t_recap)
    story.append(Spacer(1, 6 * mm))

    # ----- Arrêté -----
    total_str = _fmt_cdf(inv.total_ttc_cdf) if inv.total_ttc_cdf is not None else "—"
    story.append(Paragraph(
        f"Arrêté la présente facture à la somme de <b>{total_str}</b> francs congolais toutes taxes comprises.",
        ParagraphStyle(name="Arrete", alignment=1, fontSize=9, spaceAfter=8),
    ))
    story.append(Spacer(1, 6 * mm))

    # ----- Sécurité + QR -----
    story.append(Paragraph(
        "--- ÉLÉMENTS DE SÉCURITÉ DE LA FACTURE NORMALISÉE ---",
        ParagraphStyle(name="SecTitle", fontSize=9, textColor=colors.grey, spaceAfter=4),
    ))

    sec_lines = []
    if inv.isf:
        sec_lines.append(f"ISF : {inv.isf}")
    if inv.code_def_dgi:
        sec_lines.append(f"Code DEF/DGI : {inv.code_def_dgi}")
    if inv.def_nid:
        sec_lines.append(f"DEF NID : {inv.def_nid}")
    if inv.def_compteurs:
        sec_lines.append(f"DEF Compteurs : {inv.def_compteurs}")
    if inv.def_datetime:
        sec_lines.append(f"DEF Heure : {inv.def_datetime}")

    if sec_lines:
        story.append(Paragraph("<br/>".join(sec_lines), ParagraphStyle(name="SecBody", fontSize=8, textColor=colors.grey)))
        story.append(Spacer(1, 4 * mm))

    # QR — afficher image, sinon afficher texte
    if inv.qr_raw:
        try:
            story.append(_qr_flowable(inv.qr_raw, size_mm=30))  # 30mm plus visible
        except Exception:
            story.append(Paragraph(
                f"QR (données) : {inv.qr_raw}",
                ParagraphStyle(name="SecBody2", fontSize=8, textColor=colors.grey),
            ))
    else:
        story.append(Paragraph("QR : —", ParagraphStyle(name="SecBody2", fontSize=8, textColor=colors.grey)))

    doc.build(story)
    buffer.seek(0)
    return buffer
