"""PDF Generator for Cotizador E3 — port of pdf-generator.ts using ReportLab."""

from __future__ import annotations

import base64
import io
from datetime import datetime
from typing import Any

from reportlab.lib import colors
from reportlab.lib.pagesizes import LETTER
from reportlab.lib.units import inch
from reportlab.pdfgen import canvas
from reportlab.lib.utils import ImageReader

from app.services.calculators import FASES_SHORT, PLANES_BUCEFALO, bucefalo_precio

PRIMARY_DEFAULT = "#2563eb"
DARK_DEFAULT = "#1e293b"
MUTED = "#64748b"
BORDER = "#cbd5e1"
LIGHT_BG = "#f1f5f9"
WHITE = "#ffffff"

PAGE_W, PAGE_H = LETTER
MARGIN_TOP = 45
MARGIN_BOTTOM = 55
MARGIN_LEFT = 50
MARGIN_RIGHT = 50
CONTENT_W = PAGE_W - MARGIN_LEFT - MARGIN_RIGHT


def _hex_to_rgb(hex_color: str) -> colors.Color:
    h = hex_color.lstrip("#")
    r, g, b = int(h[0:2], 16), int(h[2:4], 16), int(h[4:6], 16)
    return colors.Color(r / 255, g / 255, b / 255)


def _fmt_currency(n: float) -> str:
    return f"${n:,.2f}"


def _fmt_date(d: datetime) -> str:
    months = [
        "enero", "febrero", "marzo", "abril", "mayo", "junio",
        "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre",
    ]
    return f"{d.day} de {months[d.month - 1]} de {d.year}"


def _load_logo(logo_base64: str | None, logo_mime: str | None) -> ImageReader | None:
    if not logo_base64:
        return None
    try:
        raw = base64.b64decode(logo_base64)
        return io.BytesIO(raw)
    except Exception:
        return None


def generate_cotizacion_pdf(data: dict[str, Any]) -> bytes:
    """Generate a professional quotation PDF.

    Args:
        data: dict with keys matching CotizacionPDFData interface:
            numero, clienteNombre, clienteEmpresa, asesorNombre, fecha, vigencia,
            moneda, tipoCambio, proyecto, esquemaPago, servicios[],
            planBucefaloNivel, planBucefaloPrecio, incluirBonos,
            configBancaria{}, colorPrimario, colorSecundario, logoBase64, logoMime
    """
    PRIMARY = data.get("colorPrimario") or PRIMARY_DEFAULT
    DARK = data.get("colorSecundario") or DARK_DEFAULT
    primary_rgb = _hex_to_rgb(PRIMARY)
    dark_rgb = _hex_to_rgb(DARK)
    muted_rgb = _hex_to_rgb(MUTED)
    border_rgb = _hex_to_rgb(BORDER)
    light_rgb = _hex_to_rgb(LIGHT_BG)
    white_rgb = _hex_to_rgb(WHITE)

    buf = io.BytesIO()
    c = canvas.Canvas(buf, pagesize=LETTER)
    c.setTitle(f"Cotizacion {data.get('numero', '')}")

    logo = _load_logo(data.get("logoBase64"), data.get("logoMime"))

    servicios = data.get("servicios", [])
    plan_nivel = data.get("planBucefaloNivel")
    plan_precio = data.get("planBucefaloPrecio", 0)
    incluir_bonos = data.get("incluirBonos", False)
    cfg_bancaria = data.get("configBancaria") or {}

    # ── PAGE 1: COVER ──────────────────────────────
    c.setFillColor(white_rgb)
    c.rect(0, 0, PAGE_W, PAGE_H, fill=1, stroke=0)

    y = PAGE_H - 80
    if logo:
        try:
            c.drawImage(logo, MARGIN_LEFT, y - 20, width=65, height=65, preserveAspectRatio=True, mask="auto")
            y -= 85
        except Exception:
            logo = None

    if not logo:
        c.setFont("Helvetica-Bold", 28)
        c.setFillColor(primary_rgb)
        c.drawString(MARGIN_LEFT, y, "UJ")
        c.setFont("Helvetica", 9)
        c.setFillColor(muted_rgb)
        c.drawString(MARGIN_LEFT + 48, y - 15, "Uriel Jareth Consulting")
        y -= 40

    bar_y = y
    c.setFillColor(primary_rgb)
    c.rect(MARGIN_LEFT, bar_y, CONTENT_W, 4, fill=1, stroke=0)

    c.setFont("Helvetica-Bold", 36)
    c.setFillColor(dark_rgb)
    c.drawString(MARGIN_LEFT, bar_y - 40, "Cotizacion")
    c.setFont("Helvetica", 18)
    c.setFillColor(primary_rgb)
    c.drawString(MARGIN_LEFT, bar_y - 65, data.get("numero", ""))

    iy = bar_y - 100
    cL = MARGIN_LEFT
    cR = MARGIN_LEFT + CONTENT_W * 0.52

    info_l = [
        ("Cliente", data.get("clienteNombre", "")),
        ("Empresa", data.get("clienteEmpresa", "")),
        ("Proyecto", data.get("proyecto", "")),
        ("Asesor", data.get("asesorNombre", "")),
    ]
    info_r = [
        ("Fecha", _fmt_date(data.get("fecha", datetime.now()))),
        ("Vigencia", _fmt_date(data.get("vigencia", datetime.now()))),
        ("Moneda", data.get("moneda", "MXN")),
        ("Esquema", data.get("esquemaPago", "")),
    ]

    for i in range(max(len(info_l), len(info_r))):
        if i < len(info_l) and info_l[i][1]:
            c.setFont("Helvetica", 9)
            c.setFillColor(muted_rgb)
            c.drawString(cL, iy, info_l[i][0])
            c.setFont("Helvetica", 11)
            c.setFillColor(dark_rgb)
            c.drawString(cL, iy - 14, info_l[i][1])
        if i < len(info_r) and info_r[i][1]:
            c.setFont("Helvetica", 9)
            c.setFillColor(muted_rgb)
            c.drawString(cR, iy, info_r[i][0])
            c.setFont("Helvetica", 11)
            c.setFillColor(dark_rgb)
            c.drawString(cR, iy - 14, str(info_r[i][1]))
        iy -= 32

    # ── PAGE 2+: RESUMEN ──────────────────────────
    c.showPage()
    y = PAGE_H - MARGIN_TOP

    if logo:
        try:
            c.drawImage(logo, MARGIN_LEFT + CONTENT_W - 70, y - 5, width=22, height=22, preserveAspectRatio=True, mask="auto")
        except Exception:
            pass

    c.setFillColor(primary_rgb)
    c.rect(MARGIN_LEFT, y - 16, 4, 16, fill=1, stroke=0)
    c.setFont("Helvetica-Bold", 15)
    c.setFillColor(dark_rgb)
    c.drawString(MARGIN_LEFT + 12, y - 15, "Hoja Resumen")
    y -= 28

    cliente_ref = data.get("clienteEmpresa") or data.get("clienteNombre", "")
    c.setFont("Helvetica", 8)
    c.setFillColor(muted_rgb)
    c.drawString(MARGIN_LEFT, y, f"En atencion a: {cliente_ref}")
    c.drawString(MARGIN_LEFT + CONTENT_W * 0.45, y, f"No. Cotizacion: {data.get('numero', '')}")
    y -= 11
    c.drawString(MARGIN_LEFT, y, f"Asesor: {data.get('asesorNombre', '')}")
    c.drawString(MARGIN_LEFT + CONTENT_W * 0.45, y, f"Fecha: {_fmt_date(data.get('fecha', datetime.now()))}  |  Moneda: {data.get('moneda', 'MXN')}")
    y -= 18

    col_nombre = MARGIN_LEFT
    col_tipo = MARGIN_LEFT + CONTENT_W - 200
    col_tiempo = MARGIN_LEFT + CONTENT_W - 120
    col_precio = MARGIN_LEFT + CONTENT_W - 60

    # Header row
    c.setFillColor(light_rgb)
    c.rect(MARGIN_LEFT, y - 2, CONTENT_W, 16, fill=1, stroke=0)
    c.setFont("Helvetica-Bold", 7)
    c.setFillColor(dark_rgb)
    c.drawString(col_nombre + 6, y + 3, "Servicio")
    c.drawString(col_tipo + 4, y + 3, "Tipo")
    c.drawString(col_tiempo + 4, y + 3, "Entrega")
    c.drawRightString(col_precio + 60, y + 3, "Precio")
    y -= 4

    c.setStrokeColor(border_rgb)
    c.setLineWidth(0.3)
    c.line(MARGIN_LEFT, y, MARGIN_LEFT + CONTENT_W, y)
    y -= 14

    unicos = [s for s in servicios if s.get("tipoPago") == "unico"]
    mensuales = [s for s in servicios if s.get("tipoPago") == "mensual"]

    def _draw_section(srv_list, tipo_label, titulo_total, y_pos):
        if not srv_list:
            return y_pos
        current_fase = -1
        max_y = PAGE_H - MARGIN_BOTTOM - 5

        for serv in srv_list:
            fase = serv.get("fase", 0)
            if fase != current_fase:
                current_fase = fase
                if y_pos - 20 < max_y - PAGE_H:
                    c.showPage()
                    y_pos = PAGE_H - MARGIN_TOP
                c.setFillColor(light_rgb)
                c.rect(MARGIN_LEFT, y_pos - 14, CONTENT_W, 14, fill=1, stroke=0)
                c.setFont("Helvetica-Bold", 7)
                c.setFillColor(primary_rgb)
                c.drawString(MARGIN_LEFT + 6, y_pos - 11, FASES_SHORT.get(fase, f"FASE {fase}"))
                y_pos -= 18

            c.setFont("Helvetica", 8)
            c.setFillColor(dark_rgb)
            nombre = serv.get("nombre", "")
            c.drawString(col_nombre + 6, y_pos - 10, nombre[:60])
            c.setFont("Helvetica", 7)
            c.setFillColor(muted_rgb)
            c.drawString(col_tipo + 4, y_pos - 10, tipo_label)
            c.drawString(col_tiempo + 4, y_pos - 10, serv.get("tiempoEntrega", "")[:15])
            c.setFont("Helvetica-Bold", 8)
            c.setFillColor(dark_rgb)
            c.drawRightString(col_precio + 60, y_pos - 10, _fmt_currency(serv.get("precio", 0)))
            y_pos -= 14

            entregables = serv.get("entregables", [])
            if entregables:
                half = (len(entregables) + 1) // 2
                for idx in range(half):
                    e1 = entregables[idx]
                    e2 = entregables[idx + half] if idx + half < len(entregables) else None
                    c.setFont("Helvetica", 6)
                    c.setFillColor(muted_rgb)
                    c.drawString(col_nombre + 10, y_pos - 8, f"\u2022 {e1[:50]}")
                    if e2:
                        c.drawString(col_nombre + CONTENT_W * 0.48, y_pos - 8, f"\u2022 {e2[:50]}")
                    y_pos -= 9

            c.setStrokeColor(_hex_to_rgb("#e5e7eb"))
            c.setLineWidth(0.2)
            c.line(col_nombre + 6, y_pos, MARGIN_LEFT + CONTENT_W, y_pos)
            y_pos -= 6

        total = sum(s.get("precio", 0) for s in srv_list)
        y_pos -= 4
        c.setFillColor(_hex_to_rgb("#f8fafc"))
        c.rect(MARGIN_LEFT, y_pos - 2, CONTENT_W, 18, fill=1, stroke=0)
        c.setFont("Helvetica-Bold", 8.5)
        c.setFillColor(primary_rgb)
        c.drawString(col_nombre + 6, y_pos + 3, titulo_total)
        c.drawRightString(col_precio + 60, y_pos + 3, _fmt_currency(total))
        y_pos -= 18
        c.setFont("Helvetica", 6)
        c.setFillColor(muted_rgb)
        c.drawString(col_nombre + 6, y_pos, "(Precios en Moneda Nacional, no incluyen IVA)")
        y_pos -= 14
        return y_pos

    if unicos:
        y = _draw_section(unicos, "Unico", "Total Pago Unico", y)
    if mensuales:
        y = _draw_section(mensuales, "Mensual", "Total Pago Mensual", y)

    if plan_nivel:
        label = plan_nivel.capitalize()
        c.setFillColor(light_rgb)
        c.rect(MARGIN_LEFT, y - 2, CONTENT_W, 14, fill=1, stroke=0)
        c.setFont("Helvetica-Bold", 7.5)
        c.setFillColor(dark_rgb)
        c.drawString(col_nombre + 6, y + 3, f"Plan Bucefalo CRM - {label}")
        c.drawRightString(col_precio + 60, y + 3, _fmt_currency(plan_precio))
        y -= 20

    if incluir_bonos:
        y -= 6
        c.setFillColor(primary_rgb)
        c.rect(MARGIN_LEFT, y - 10, 3, 10, fill=1, stroke=0)
        c.setFont("Helvetica-Bold", 9)
        c.setFillColor(dark_rgb)
        c.drawString(MARGIN_LEFT + 10, y - 8, "Bonos (Pago en una exhibicion)")
        y -= 20
        bonos = [
            "Bono 1: 30 min mensuales en servicios Centinela (Sitio Web)",
            "Bono 2: Workshop Estrategico de Buyer Persona",
            "Bono 3: Workshop de Propuestas de Valor y Oferta Irresistible",
            "Bono 4: 1 ano de Membresia Premium",
            "Bono 5: Un mes gratis de Bucefalo CRM",
            "Bono 6: Script de Ventas con mas de 100 complementos",
        ]
        for b in bonos:
            c.setFont("Helvetica", 7)
            c.setFillColor(dark_rgb)
            c.drawString(MARGIN_LEFT + 8, y - 8, f"\u2713  {b}")
            y -= 12

    # ── T&C PAGE ──────────────────────────────────
    c.showPage()
    y = PAGE_H - MARGIN_TOP

    if logo:
        try:
            c.drawImage(logo, MARGIN_LEFT + CONTENT_W - 70, y - 5, width=22, height=22, preserveAspectRatio=True, mask="auto")
        except Exception:
            pass

    c.setFillColor(primary_rgb)
    c.rect(MARGIN_LEFT, y - 16, 4, 16, fill=1, stroke=0)
    c.setFont("Helvetica-Bold", 15)
    c.setFillColor(dark_rgb)
    c.drawString(MARGIN_LEFT + 12, y - 15, "Terminos y Condiciones")
    y -= 30

    def _section_title(title, yy):
        c.setFillColor(primary_rgb)
        c.rect(MARGIN_LEFT, yy - 9, 3, 9, fill=1, stroke=0)
        c.setFont("Helvetica-Bold", 9)
        c.setFillColor(dark_rgb)
        c.drawString(MARGIN_LEFT + 10, yy - 8, title)
        return yy - 20

    def _draw_bullets(title, items, yy):
        yy = _section_title(title, yy)
        for t in items:
            c.setFont("Helvetica", 7.5)
            c.setFillColor(dark_rgb)
            # Simple text wrapping
            words = t.split()
            line = ""
            for word in words:
                test = f"{line} {word}".strip()
                if c.stringWidth(test, "Helvetica", 7.5) > CONTENT_W - 10:
                    c.drawString(MARGIN_LEFT + 2, yy - 8, f"\u2022  {line}")
                    yy -= 11
                    line = word
                else:
                    line = test
            if line:
                c.drawString(MARGIN_LEFT + 2, yy - 8, f"\u2022  {line}")
                yy -= 11
        return yy - 8

    y = _draw_bullets("Condiciones", [
        "Esta cotizacion tiene una vigencia de 15 dias habiles.",
        "Cualquier ajuste al proyecto despues de la aprobacion del contenido afectara la fecha de entrega y por consiguiente el costo.",
        "El cliente debera proporcionar la informacion solicitada por Uriel Jareth Consulting en tiempo y forma.",
        "Si la falta de informacion provoca un excedente en los plazos de entrega del proyecto, las horas adicionales de servicio se cotizaran por separado.",
        "Los pagos correspondientes a los servicios mensuales deberan realizarse en los primeros 5 dias del mes.",
        "Todo el material e informacion necesarios para la realizacion del sitio web deberan ser entregados en un plazo maximo de 40 dias naturales a partir del arranque del proyecto.",
    ], y)

    y = _draw_bullets("Que no incluye el proyecto?", [
        "Generacion de disenos, videos, traducciones, cambios de divisas y unidades, o cualquier servicio externo a lo cotizado.",
        "Redaccion de entradas de Blog.",
        "Integracion de Servicios de terceros ajenos a los cotizados.",
        "Servicio de Recuperacion de Accesos de: Google Analytics, Google Tag Manager, Google Search Console, Google Ads, y Meta Ads.",
        "Creacion de Redes Sociales (En caso de requerir el servicio incluira un costo adicional).",
    ], y)

    y = _draw_bullets("Notas", [
        "El presente proyecto debera tener un responsable oficial.",
        "La Hora Centinela tiene un precio de $700.00 MXN.",
        "Los archivos editables/fuente (AI, PSD) son propiedad intelectual de la agencia. Si requiere los archivos editables, estos pueden ser adquiridos abonando una tarifa de liberacion (buy-out fee).",
        "Si el proyecto se pausa por razones ajenas a Uriel Jareth Consulting, esto generara costo extra del 15% al 30% para retomar el proyecto.",
    ], y)

    y -= 8
    c.setFillColor(primary_rgb)
    c.rect(MARGIN_LEFT, y - 9, 3, 9, fill=1, stroke=0)
    c.setFont("Helvetica-Bold", 9)
    c.setFillColor(dark_rgb)
    c.drawString(MARGIN_LEFT + 10, y - 8, "Datos Bancarios")
    y -= 20

    razon_social = cfg_bancaria.get("razon_social", "URIEL JARETH ALVARADO ORTIZ")
    rfc = cfg_bancaria.get("rfc", "AAOU970201SU7")
    clabe_nac = cfg_bancaria.get("clabe_interbancaria", cfg_bancaria.get("cuenta_nacional", ""))
    cuenta_nac = cfg_bancaria.get("cuenta_nacional", "")
    banco_nac = "BBVA" if cuenta_nac else ""

    box_h = 48
    c.setFillColor(light_rgb)
    c.setStrokeColor(border_rgb)
    c.rect(MARGIN_LEFT, y - box_h, CONTENT_W, box_h, fill=1, stroke=1)
    c.setFont("Helvetica-Bold", 7)
    c.setFillColor(dark_rgb)
    c.drawString(MARGIN_LEFT + 8, y - 12, "Transferencia Nacional")
    c.setFont("Helvetica", 6.5)
    if cuenta_nac:
        c.drawString(MARGIN_LEFT + 8, y - 24, f"Cuenta: {cuenta_nac}")
    if clabe_nac:
        c.drawString(MARGIN_LEFT + CONTENT_W * 0.45, y - 24, f"CLABE: {clabe_nac}")
    c.drawString(MARGIN_LEFT + 8, y - 35, f"Razon Social: {razon_social}")
    c.drawString(MARGIN_LEFT + CONTENT_W * 0.45, y - 35, f"RFC: {rfc}")
    if banco_nac:
        c.drawString(MARGIN_LEFT + 8, y - 46, f"Banco: {banco_nac}")
    y -= box_h + 8

    c.setFillColor(light_rgb)
    c.rect(MARGIN_LEFT, y - box_h, CONTENT_W, box_h, fill=1, stroke=1)
    c.setFont("Helvetica-Bold", 7)
    c.setFillColor(dark_rgb)
    c.drawString(MARGIN_LEFT + 8, y - 12, "Transferencia Internacional")
    c.setFont("Helvetica", 6.5)
    c.drawString(MARGIN_LEFT + 8, y - 24, f"Beneficiario: {razon_social}")
    c.drawString(MARGIN_LEFT + 8, y - 35, "Banco: BBVA Mexico")
    c.drawString(MARGIN_LEFT + CONTENT_W * 0.45, y - 35, "SWIFT: BCMRMXMMPYM")

    # ── FOOTER ON ALL PAGES ──────────────────────
    page_count = c.getPageNumber()
    for i in range(1, page_count + 1):
        c.setPageSize(LETTER)
        c.setFont("Helvetica", 6)
        c.setFillColor(muted_rgb)
        c.setStrokeColor(border_rgb)
        c.setLineWidth(0.5)
        c.line(MARGIN_LEFT, MARGIN_BOTTOM - 10, MARGIN_LEFT + CONTENT_W, MARGIN_BOTTOM - 10)
        c.drawCentredString(PAGE_W / 2, MARGIN_BOTTOM - 22, "Uriel Jareth Consulting")
        c.drawCentredString(PAGE_W / 2, MARGIN_BOTTOM - 32, "urieljareth.com  |  contacto@urieljareth.com  |  (445) 182 9943")

    c.save()
    return buf.getvalue()
