from reportlab.platypus import (
    SimpleDocTemplate,
    Paragraph,
    Spacer,
    Table,
    TableStyle,
    PageBreak,
)
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.colors import HexColor
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import mm
from pathlib import Path
import os
from typing import Dict, Any, Optional

from shared.branding import get_color, app_logo_path

# ==========================
# Branding helpers (colores)
# ==========================

def _hx(section: str, key: str, default: str) -> HexColor:
    return HexColor(get_color(section, key, default) or default)

BRAND_BLUE     = _hx("brand",   "blue600",    "#0F4F9A")
BRAND_DARK     = _hx("brand",   "blue900",    "#0A2A55")
APP_WP_INVOICE = _hx("apps",    "wp_invoices", "#33A9FF")
APP_ABN_LOOKUP = _hx("apps",    "abn_lookup_app", "#9747FF")

NEUTRAL_100    = _hx("neutral", "neutral100", "#F6F6F9")
NEUTRAL_300    = _hx("neutral", "neutral300", "#E2E2E6")
NEUTRAL_500    = _hx("neutral", "neutral500", "#A7A7AD")
NEUTRAL_900    = _hx("neutral", "neutral900", "#1B1B1F")

STATE_SUCCESS  = _hx("states",  "success", "#15B66D")
STATE_WARNING  = _hx("states",  "warning", "#F6A700")
STATE_ERROR    = _hx("states",  "error",   "#D0342C")
STATE_INFO     = _hx("states",  "info",    "#2196F3")

def _draw_brand_header(canvas, doc):
    """
    Header corporativo minimalista:
    - Barra azul en la parte superior
    - Logo de wp_invoices (si existe)
    - Título corto de reporte
    """
    canvas.saveState()

    page_width, page_height = doc.pagesize
    header_h = 16 * mm

    # Barra azul superior
    canvas.setFillColor(BRAND_BLUE)
    canvas.rect(0, page_height - header_h, page_width, header_h, fill=1, stroke=0)

    # Logo de la app (si existe)
    try:
        logo_path = app_logo_path("wp_invoices")
        if logo_path.is_file():
            logo_h = header_h - 4
            logo_w = logo_h * 1.4
            canvas.drawImage(
                str(logo_path),
                doc.leftMargin,
                page_height - header_h + 2,
                width=logo_w,
                height=logo_h - 4,
                preserveAspectRatio=True,
                mask="auto",
            )
            text_x = doc.leftMargin + logo_w + 6
        else:
            text_x = doc.leftMargin + 4
    except Exception:
        text_x = doc.leftMargin + 4

    # Título del header
    canvas.setFillColor(colors.white)
    canvas.setFont("Helvetica-Bold", 10)
    canvas.drawString(text_x, page_height - header_h / 2 + 3, "WP Invoices – Digital Extract")

    canvas.restoreState()


def create_invoice_revision_pdf(
    extracted: Dict[str, Any],
    output_dir: str,
    original_filename: str,
    checks: Optional[Dict[str, Any]] = None,
) -> str:
    """
    Layout universal v1 con branding:

    Página 1:
      - Header corporativo
      - Título
      - DOS COLUMNAS:
        Izquierda: Header Information, Supplier Details, Buyer Details
        Derecha: Payment Info (as printed), Internal Payment Information

    Página 2+:
      - Line Items (tabla con repeatRows)

    Página final:
      - Financial Summary
      - Validation Checks
      - ABN Lookup (si aplica)
    """

    # -------------------------------
    # 0. Paths y documento
    # -------------------------------
    out_path = Path(output_dir)
    out_path.mkdir(parents=True, exist_ok=True)

    safe_name = original_filename or "invoice"
    stem = os.path.splitext(safe_name)[0]
    pdf_path = out_path / f"{stem}_universal.pdf"

    styles = getSampleStyleSheet()

    H1 = ParagraphStyle(
        "H1",
        parent=styles["Heading1"],
        fontSize=15,
        leading=18,
        spaceAfter=6,
        textColor=NEUTRAL_900,
    )
    H2 = ParagraphStyle(
        "H2",
        parent=styles["Heading2"],
        fontSize=12,
        leading=14,
        spaceBefore=6,
        spaceAfter=4,
        textColor=NEUTRAL_900,
    )
    normal = styles["Normal"]
    normal.textColor = NEUTRAL_900
    small = ParagraphStyle("small", parent=normal, fontSize=8, leading=9, textColor=NEUTRAL_900)
    small_item = ParagraphStyle("small_item", parent=small, fontSize=7.5, leading=9)

    doc = SimpleDocTemplate(
        str(pdf_path),
        pagesize=A4,
        leftMargin=22 * mm,
        rightMargin=22 * mm,
        topMargin=25 * mm,   # un poco más para dar espacio al header
        bottomMargin=20 * mm,
    )

    page_width, _ = A4
    content_width = page_width - doc.leftMargin - doc.rightMargin
    col_width = content_width / 2.0

    story = []

    # Helper para acceder a rutas tipo "header.invoice.date.issue_date.verbatim"
    def get_node(path: str, default=None):
        parts = path.split(".")
        node: Any = extracted
        for p in parts:
            if not isinstance(node, dict):
                return default
            node = node.get(p)
            if node is None:
                return default
        return node if node is not None else default

    # -------------------------------
    # 1. Título + disclaimer
    # -------------------------------
    inv_number = get_node("header.invoice.number.verbatim")
    inv_date = get_node("header.invoice.date.issue_date.verbatim")
    supplier_name = get_node("header.supplier.name.verbatim")

    title_text = f"{supplier_name or 'Supplier'} – Invoice Extract – {inv_number or 'N/A'} – {inv_date or 'N/A'}"
    story.append(Paragraph(title_text, H1))

    disclaimer = (
        f'<font size="7" color="{NEUTRAL_500.hexval()}">'
        "This document is an automatically generated digital extract from an original supplier invoice. "
        "It is NOT a legally issued tax invoice."
        "</font>"
    )
    story.append(Paragraph(disclaimer, small))
    story.append(Spacer(1, 6))

    # -------------------------------
    # 2. Bloques de resumen (dos columnas)
    # -------------------------------

    # 2.1 Header Information
    header_data = [
        ["Invoice Number:", inv_number or "N/A"],
        ["Issue Date:", inv_date or "N/A"],
        ["Invoice Type:", get_node("invoice_type.verbatim") or "N/A"],
    ]
    header_tbl = Table(header_data, colWidths=[30 * mm, col_width - 30 * mm])
    header_tbl.setStyle(TableStyle([
        ("BACKGROUND", (0, 0), (0, -1), NEUTRAL_100),
        ("TEXTCOLOR", (0, 0), (0, -1), NEUTRAL_900),

        ("FONTNAME", (0, 0), (-1, -1), "Helvetica"),
        ("FONTSIZE", (0, 0), (-1, -1), 9),
        ("BOTTOMPADDING", (0, 0), (-1, -1), 3),

        ("GRID", (0, 0), (-1, -1), 0.25, NEUTRAL_300),
    ]))

    # 2.2 Supplier Details
    sup = extracted.get("header", {}).get("supplier", {}) or {}
    sup_name = (
        sup.get("name", {}).get("verbatim")
        or sup.get("name", {}).get("computed")
        or ""
    )
    sup_abn = (
        sup.get("abn", {}).get("verbatim")
        or sup.get("abn", {}).get("computed")
        or ""
    )
    sup_address = sup.get("address", {}).get("verbatim") or sup.get("address", {}).get("computed")
    supplier_table = [
        ["Name", sup_name],
        ["ABN", sup_abn],
        ["Address", Paragraph(sup_address or "", small)],
        ["Phone", sup.get("phone", {}).get("verbatim", {})],
        ["Email", sup.get("email", {}).get("verbatim", {})],
    ]
    supplier_tbl = Table(supplier_table, colWidths=[25 * mm, col_width - 25 * mm])
    supplier_tbl.setStyle(TableStyle([
        ("BACKGROUND", (0, 0), (0, -1), NEUTRAL_100),
        ("FONTNAME", (0, 0), (-1, -1), "Helvetica"),
        ("FONTSIZE", (0, 0), (-1, -1), 9),
        ("BOTTOMPADDING", (0, 0), (-1, -1), 3),
        ("GRID", (0, 0), (-1, -1), 0.25, NEUTRAL_300),
    ]))

    # 2.3 Buyer Details
    buyer = extracted.get("header", {}).get("buyer", {}) or {}
    printed_address = (buyer.get("address") or {}).get("verbatim") if isinstance(buyer.get("address"), dict) else "None"
    buyer_table = [
        ["Name", (buyer.get("name") or {}).get("verbatim")],
        ["ABN", (buyer.get("abn") or {}).get("verbatim")],
        ["Address", Paragraph(printed_address, small)],
        ["Phone", (buyer.get("phone") or {}).get("verbatim") if isinstance(buyer.get("phone"), dict) else None],
        ["Email", (buyer.get("email") or {}).get("verbatim") if isinstance(buyer.get("email"), dict) else None],
    ]
    buyer_tbl = Table(buyer_table, colWidths=[25 * mm, col_width - 25 * mm])
    buyer_tbl.setStyle(TableStyle([
        ("BACKGROUND", (0, 0), (0, -1), NEUTRAL_100),
        ("FONTNAME", (0, 0), (-1, -1), "Helvetica"),
        ("FONTSIZE", (0, 0), (-1, -1), 9),
        ("BOTTOMPADDING", (0, 0), (-1, -1), 3),
        ("GRID", (0, 0), (-1, -1), 0.25, NEUTRAL_300),
    ]))

    # 2.4 Payment Info (as printed)
    pp = extracted.get("payment_printed", {}) or {}
    printed_rows = [
        ["Printed Status:", (pp.get("status") or {}).get("verbatim")],
        ["Amount Paid:", (pp.get("amount_paid") or {}).get("verbatim")],
        ["Balance Due:", (pp.get("balance_due") or {}).get("verbatim")],
        ["Method:", (pp.get("method") or {}).get("verbatim")],
        ["Reference:", (pp.get("reference") or {}).get("verbatim")],
    ]
    printed_tbl = Table(printed_rows, colWidths=[30 * mm, col_width - 30 * mm])
    printed_tbl.setStyle(TableStyle([
        ("BACKGROUND", (0, 0), (0, -1), NEUTRAL_100),
        ("FONTNAME", (0, 0), (-1, -1), "Helvetica"),
        ("FONTSIZE", (0, 0), (-1, -1), 9),
        ("BOTTOMPADDING", (0, 0), (-1, -1), 3),
        ("GRID", (0, 0), (-1, -1), 0.25, NEUTRAL_300),
    ]))

    printed_caption = Paragraph(
        f"""<font size="7" color="{NEUTRAL_500.hexval()}">
        Payment info above is shown exactly as printed on the supplier document.
        Actual reconciliation is done in Xero / AroFlo.
        </font>""",
        small,
    )

    # 2.5 Internal Payment Information
    pi = extracted.get("payment_interpretation", {}) or {}
    pi_status = pi.get("suggested_internal_status") or ""
    pi_flag = str(pi.get("is_pos_fully_paid")) if "is_pos_fully_paid" in pi else ""
    pi_notes_text = pi.get("notes") or ""

    interp_rows = [
        ["Internal Status:", pi_status],
        ["POS Fully Paid:", pi_flag],
        ["Notes:", Paragraph(pi_notes_text, small)],
    ]
    interp_tbl = Table(interp_rows, colWidths=[30 * mm, col_width - 30 * mm])
    interp_tbl.setStyle(TableStyle([
        ("BACKGROUND", (0, 0), (0, -1), NEUTRAL_100),
        ("FONTNAME", (0, 0), (-1, -1), "Helvetica"),
        ("FONTSIZE", (0, 0), (-1, -1), 9),
        ("VALIGN", (0, 0), (-1, -1), "TOP"),
        ("BOTTOMPADDING", (0, 0), (-1, -1), 3),
        ("GRID", (0, 0), (-1, -1), 0.25, NEUTRAL_300),
    ]))

    # 2.6 Empaquetar cada columna en su propia tabla vertical
    left_rows = [
        [Paragraph("Header Information", H2)],
        [header_tbl],
        [Spacer(1, 12)],
        [Paragraph("Supplier Details", H2)],
        [supplier_tbl],
        [Spacer(1, 12)],
        [Paragraph("Buyer Details", H2)],
        [buyer_tbl],
    ]
    left_col_table = Table(left_rows, colWidths=[col_width])
    left_col_table.setStyle(TableStyle([
        ("VALIGN", (0, 0), (-1, -1), "TOP"),
        ("LEFTPADDING", (0, 0), (-1, -1), 0),
        ("RIGHTPADDING", (0, 0), (-1, -1), 6),
        ("TOPPADDING", (0, 0), (-1, -1), 0),
        ("BOTTOMPADDING", (0, 0), (-1, -1), 0),
    ]))

    right_rows = [
        [Paragraph("Payment Info (as printed)", H2)],
        [printed_tbl],
        [Spacer(1, 12)],
        [printed_caption],
        [Spacer(1, 12)],
        [Paragraph("Internal Payment Information", H2)],
        [interp_tbl],
    ]
    right_col_table = Table(right_rows, colWidths=[col_width])
    right_col_table.setStyle(TableStyle([
        ("VALIGN", (0, 0), (-1, -1), "TOP"),
        ("LEFTPADDING", (0, 0), (-1, -1), 6),
        ("RIGHTPADDING", (0, 0), (-1, -1), 0),
        ("TOPPADDING", (0, 0), (-1, -1), 0),
        ("BOTTOMPADDING", (0, 0), (-1, -1), 0),
    ]))

    two_col_summary = Table(
        [[left_col_table, right_col_table]],
        colWidths=[col_width, col_width],
        hAlign="LEFT",
    )
    two_col_summary.setStyle(TableStyle([
        ("VALIGN", (0, 0), (-1, -1), "TOP"),
        ("LEFTPADDING", (0, 0), (-1, -1), 0),
        ("RIGHTPADDING", (0, 0), (-1, -1), 0),
        ("TOPPADDING", (0, 0), (-1, -1), 0),
        ("BOTTOMPADDING", (0, 0), (-1, -1), 0),
    ]))

    story.append(two_col_summary)

    # -------------------------------
    # 3. Página(s) de Line Items
    # -------------------------------
    story.append(PageBreak())
    story.append(Paragraph("Line Items", H2))

    items = extracted.get("items", []) or []

    table_header = ["SKU", "Description", "Qty", "Unit Price", "Discount", "GST", "Line Total"]
    table_rows = [[Paragraph(h, small_item) for h in table_header]]

    for item in items:
        def field(it, key):
            node = it.get(key) or {}
            return node.get("verbatim") or node.get("computed") or ""

        sku = field(item, "sku")
        desc = field(item, "description")
        qty = field(item, "qty")
        unit = field(item, "unit_price")
        disc = field(item, "discount")
        gst_line = field(item, "gst_line")
        line_total = field(item, "line_total")

        row = [
            Paragraph(str(sku), small_item),
            Paragraph(str(desc), small_item),
            Paragraph(str(qty), small_item),
            Paragraph(str(unit), small_item),
            Paragraph(str(disc), small_item),
            Paragraph(str(gst_line), small_item),
            Paragraph(str(line_total), small_item),
        ]
        table_rows.append(row)

    if table_rows:
        items_tbl = Table(
            table_rows,
            colWidths=[18 * mm, 70 * mm, 10 * mm, 18 * mm, 18 * mm, 14 * mm, 20 * mm],
            repeatRows=1,
        )
        items_tbl.setStyle(TableStyle([
            ("GRID", (0, 0), (-1, -1), 0.25, NEUTRAL_300),
            ("BACKGROUND", (0, 0), (-1, 0), APP_WP_INVOICE),
            ("TEXTCOLOR", (0, 0), (-1, 0), colors.white),
            ("VALIGN", (0, 0), (-1, -1), "TOP"),
        ]))
        story.append(items_tbl)
    else:
        story.append(Paragraph("No line items found.", small))

    # -------------------------------
    # 4. Página final: Summary + Validations
    # -------------------------------
    story.append(PageBreak())

    totals = extracted.get("totals", {}) or {}

    def tval(key: str):
        node = totals.get(key) or {}
        return node.get("verbatim") or node.get("computed")

    summary_rows = [
        ["Subtotal", str(tval("subtotal"))],
        ["Discount Global", str(tval("discount_global"))],
        ["Freight", str(tval("freight"))],
        ["Surcharges", str(tval("surcharge_total"))],
        ["Rounding", str(tval("rounding"))],
        ["GST", str(tval("gst"))],
        ["Grand Total", str(tval("grand_total"))],
        ["GST Basis", totals.get("gst_basis", "")],
    ]

    summary_tbl = Table(summary_rows, colWidths=[40 * mm, 80 * mm])
    summary_tbl.setStyle(TableStyle([
        ("BACKGROUND", (0, 0), (1, 0), NEUTRAL_100),
        ("FONTNAME", (0, 0), (-1, -1), "Helvetica"),
        ("FONTSIZE", (0, 0), (-1, -1), 9),
        ("GRID", (0, 0), (-1, -1), 0.25, NEUTRAL_300),
    ]))

    story.append(Paragraph("Financial Summary", H2))
    story.append(summary_tbl)
    story.append(Spacer(1, 10))

    # ABN Lookup (básico), si hay checks
    if checks:
        tax_lookup_basic = checks.get("tax_lookup_basic")
        if tax_lookup_basic:
            story.extend(build_tax_lookup_basic_section(tax_lookup_basic, H2, small))

    # Validaciones internas
    validations = totals.get("validations", {}) or {}
    story.append(Paragraph("Validation Checks", H2))

    validation_rows = []
    if validations:
        for key, value in validations.items():
            validation_rows.append([key, "\u2714" if value else "\u2718"])
        validations_tbl = Table(validation_rows, colWidths=[80 * mm, 40 * mm])
        validations_tbl.setStyle(TableStyle([
            ("BACKGROUND", (0, 0), (0, -1), NEUTRAL_100),
            ("FONTNAME", (0, 0), (-1, -1), "Helvetica"),
            ("FONTSIZE", (0, 0), (-1, -1), 9),
            ("BOTTOMPADDING", (0, 0), (-1, -1), 3),
            ("GRID", (0, 0), (-1, -1), 0.25, NEUTRAL_300),
        ]))
        story.append(validations_tbl)
    else:
        story.append(Paragraph("No validations available.", small))

    story.append(Spacer(1, 10))

    minimum_ato_symbol = "\u2714" if extracted.get("minimum_ato", False) else "\u2718"
    minumym_xero_symbol = "\u2714" if extracted.get("minimum_xero_aeroflo", False) else "\u2718"
    data_validated_symbol = "\u2714" if extracted.get("date_validated", False) else "\u2718"

    story.append(Paragraph(
        f"minimum_ato: <b>{minimum_ato_symbol}</b> – "
        f"minimum_xero_aeroflo: <b>{minumym_xero_symbol}</b> – "
        f"date_validated: <b>{data_validated_symbol}</b>",
        small,
    ))

    # -------------------------------
    # 5. Build PDF con header de marca
    # -------------------------------
    doc.build(
        story,
        onFirstPage=_draw_brand_header,
        onLaterPages=_draw_brand_header,
    )
    return str(pdf_path)

def build_tax_lookup_basic_section(
    tax_lookup_basic: Dict[str, Any],
    H2: ParagraphStyle,
    small: ParagraphStyle,
):
    """
    Construye la sección de ABN Lookup (básico) como una lista de Flowables
    con branding consistente.
    """
    elements = []

    # Título
    elements.append(Paragraph("Supplier Registry Lookup (ABN – basic)", H2))

    abn = tax_lookup_basic.get("tax_id") or "N/A"
    entity_name = tax_lookup_basic.get("entity_name") or "No disponible"

    abn_exists = bool(tax_lookup_basic.get("abn_exists"))
    is_active = bool(tax_lookup_basic.get("is_active"))
    gst_registered = bool(tax_lookup_basic.get("gst_registered"))

    if not abn_exists:
        estado_abn = "No encontrado en el registro oficial"
    else:
        estado_abn = "Activo" if is_active else "Inactivo / Cancelado"

    if gst_registered:
        gst_text = "Registrado para GST"
    else:
        gst_text = "No registrado para GST (o sin información)"

    table_data = [
        ["ABN", abn],
        ["Nombre registrado", entity_name],
        ["Estado ABN", estado_abn],
        ["GST", gst_text],
    ]

    tbl = Table(table_data, colWidths=[35 * mm, 90 * mm])
    tbl.setStyle(TableStyle([
        # Primera columna con color de app ABN Lookup
        ("BACKGROUND", (0, 0), (0, -1), APP_ABN_LOOKUP),
        ("TEXTCOLOR", (0, 0), (0, -1), colors.white),

        ("FONTNAME", (0, 0), (-1, -1), "Helvetica"),
        ("FONTSIZE", (0, 0), (-1, -1), 9),
        ("BOTTOMPADDING", (0, 0), (-1, -1), 3),
        ("VALIGN", (0, 0), (-1, -1), "TOP"),

        ("GRID", (0, 0), (-1, -1), 0.25, NEUTRAL_300),
    ]))

    elements.append(tbl)
    elements.append(Spacer(1, 4))

    note_html = (
        f'<font size="7" color="{NEUTRAL_500.hexval()}">'
        'Information provided by tax lookup service (basic version). '
        'For extended validation, connect the full ABN Lookup app.'
        '</font>'
    )
    elements.append(Paragraph(note_html, small))
    elements.append(Spacer(1, 8))

    return elements
