"""
PDF generation for invoices and receipts (Billing module).
"""
from io import BytesIO
from datetime import datetime
from reportlab.lib import colors
from reportlab.lib.pagesizes import A4
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import cm, mm
from reportlab.platypus import (
    SimpleDocTemplate, Table, TableStyle,
    Paragraph, Spacer, HRFlowable
)
from reportlab.lib.enums import TA_CENTER, TA_RIGHT, TA_LEFT

# Brand colors
PRIMARY = colors.HexColor("#1A3C5E")
ACCENT = colors.HexColor("#E8A020")
LIGHT_GREY = colors.HexColor("#F5F5F5")
MID_GREY = colors.HexColor("#CCCCCC")

PAYMENT_METHOD_LABELS = {
    "cash": "Espèces",
    "credit_card": "Carte de crédit",
    "debit_card": "Carte de débit",
    "bank_transfer": "Virement bancaire",
    "check": "Chèque",
    "mobile_payment": "Paiement mobile",
    "wave": "Wave",
    "orange_money": "Orange Money",
    "free_money": "Free Money",
    "voucher": "Bon / Voucher",
    "credit": "Crédit",
    "other": "Autre",
}

SERVICE_CATEGORY_LABELS = {
    "accommodation": "Hébergement",
    "restaurant": "Restaurant",
    "bar": "Bar",
    "room_service": "Room Service",
    "spa": "Spa & Bien-être",
    "laundry": "Blanchisserie",
    "minibar": "Minibar",
    "parking": "Parking",
    "telephone": "Téléphone",
    "transport": "Transport",
    "excursion": "Excursion",
    "boutique": "Boutique",
    "misc": "Divers",
}


def _build_styles():
    styles = getSampleStyleSheet()
    title_style = ParagraphStyle(
        "BillTitle", parent=styles["Heading1"],
        fontSize=20, alignment=TA_CENTER,
        textColor=PRIMARY, spaceAfter=6,
        fontName="Helvetica-Bold"
    )
    subtitle_style = ParagraphStyle(
        "BillSubtitle", parent=styles["Normal"],
        fontSize=10, alignment=TA_CENTER,
        textColor=ACCENT, spaceAfter=20,
        fontName="Helvetica-Bold"
    )
    header_style = ParagraphStyle(
        "BillHeader", parent=styles["Normal"],
        fontSize=9, alignment=TA_LEFT,
        leading=13
    )
    right_style = ParagraphStyle(
        "BillRight", parent=styles["Normal"],
        fontSize=9, alignment=TA_RIGHT,
        leading=13
    )
    label_style = ParagraphStyle(
        "BillLabel", parent=styles["Normal"],
        fontSize=8, textColor=colors.grey
    )
    footer_style = ParagraphStyle(
        "BillFooter", parent=styles["Normal"],
        fontSize=8, alignment=TA_CENTER,
        textColor=colors.grey, fontName="Helvetica-Oblique"
    )
    return {
        "title": title_style, "subtitle": subtitle_style,
        "header": header_style, "right": right_style,
        "label": label_style, "footer": footer_style,
        "normal": styles["Normal"]
    }


def generate_invoice_pdf(invoice, establishment=None) -> bytes:
    """
    Generate a professional invoice PDF.

    Args:
        invoice: Invoice model instance with items, receipts, client, establishment loaded
        establishment: Optional Establishment override

    Returns:
        PDF bytes
    """
    buffer = BytesIO()
    doc = SimpleDocTemplate(
        buffer, pagesize=A4,
        rightMargin=1.8*cm, leftMargin=1.8*cm,
        topMargin=1.5*cm, bottomMargin=2*cm
    )

    s = _build_styles()
    story = []

    # ── Header Block ──────────────────────────────────────────────────────
    est = establishment or (invoice.establishment if hasattr(invoice, 'establishment') else None)
    est_name = est.name if est else "FiHotelFlow"
    est_address = f"{est.address or ''}, {est.city or ''}" if est else ""
    est_phone = est.phone or "" if est else ""
    est_email = est.email or "" if est else ""
    est_tax = getattr(est, 'tax_id', '') or ""

    story.append(Paragraph(est_name, s["title"]))
    story.append(Paragraph(
        f"{est_address} | Tél: {est_phone} | {est_email}",
        s["subtitle"]
    ))
    story.append(HRFlowable(width="100%", thickness=2, color=PRIMARY))
    story.append(Spacer(1, 0.4*cm))

    # ── Invoice Reference Block ─────────────────────────────────────────
    inv_type_labels = {
        "accommodation": "FACTURE HÉBERGEMENT",
        "services": "FACTURE SERVICES",
        "mixed": "FACTURE",
        "proforma": "FACTURE PROFORMA",
        "credit_note": "NOTE DE CRÉDIT / AVOIR",
    }
    doc_title = inv_type_labels.get(invoice.invoice_type.value if hasattr(invoice.invoice_type, 'value') else invoice.invoice_type, "FACTURE")

    story.append(Paragraph(f"{doc_title} N° {invoice.invoice_number}", ParagraphStyle(
        "DocTitle", parent=s["title"], fontSize=16, textColor=PRIMARY, spaceBefore=4
    )))
    story.append(Spacer(1, 0.3*cm))

    # ── Two Column: Client + Invoice Info ────────────────────────────────
    client_name = invoice.client_name or (invoice.client.full_name if invoice.client else "Client")
    client_email = invoice.client_email or (invoice.client.email if invoice.client else "")
    client_address = invoice.client_address or ""
    client_tax = invoice.client_tax_id or (getattr(invoice.client, 'tax_id', '') if invoice.client else "")

    client_block = f"""
<b>Facturer à:</b><br/>
<b>{client_name}</b><br/>
{f'{client_address}<br/>' if client_address else ''}
{f'{client_email}<br/>' if client_email else ''}
{f'N° TVA / NINEA: {client_tax}' if client_tax else ''}
"""
    issue_date = invoice.issue_date.strftime("%d/%m/%Y") if invoice.issue_date else datetime.now().strftime("%d/%m/%Y")
    due_date = invoice.due_date.strftime("%d/%m/%Y") if invoice.due_date else "À réception"
    reservation_ref = ""
    if invoice.reservation_id:
        res = invoice.reservation
        if res:
            reservation_ref = f"<b>Réservation:</b> {res.confirmation_number}<br/>"
            reservation_ref += f"<b>Chambre:</b> {res.room.room_number if res.room else ''}<br/>"
            reservation_ref += f"<b>Arrivée:</b> {res.check_in_date.strftime('%d/%m/%Y')}<br/>"
            reservation_ref += f"<b>Départ:</b> {res.check_out_date.strftime('%d/%m/%Y')}<br/>"

    inv_block = f"""
<b>Date d'émission:</b> {issue_date}<br/>
<b>Date d'échéance:</b> {due_date}<br/>
{reservation_ref}
{f'<b>N° TVA Hôtel:</b> {est_tax}<br/>' if est_tax else ''}
<b>Statut:</b> {_status_label(invoice.status)}
"""

    two_col = Table(
        [[Paragraph(client_block, s["header"]), Paragraph(inv_block, s["right"])]],
        colWidths=[9*cm, 8*cm]
    )
    two_col.setStyle(TableStyle([('VALIGN', (0, 0), (-1, -1), 'TOP')]))
    story.append(two_col)
    story.append(Spacer(1, 0.5*cm))
    story.append(HRFlowable(width="100%", thickness=0.5, color=MID_GREY))
    story.append(Spacer(1, 0.3*cm))

    # ── Items Table ───────────────────────────────────────────────────────
    story.append(Paragraph("<b>Détail des prestations</b>", s["header"]))
    story.append(Spacer(1, 0.2*cm))

    header_row = ["Date", "Catégorie", "Description", "Qté", "P.U. HT", "TVA", "Total TTC"]
    items_data = [header_row]

    active_items = [i for i in invoice.items if not i.is_cancelled]
    for item in active_items:
        cat_label = SERVICE_CATEGORY_LABELS.get(
            item.service_category.value if hasattr(item.service_category, 'value') else item.service_category,
            str(item.service_category)
        )
        items_data.append([
            item.service_date.strftime("%d/%m/%Y") if item.service_date else "-",
            cat_label,
            item.description[:50],
            f"{item.quantity:.2f} {item.unit}",
            f"{item.unit_price_ht:,.0f}",
            f"{item.tax_rate:.0f}%",
            f"{item.total_ttc:,.0f}",
        ])

    items_table = Table(
        items_data,
        colWidths=[2*cm, 2.5*cm, 6.5*cm, 2*cm, 2.2*cm, 1.3*cm, 2.5*cm]
    )
    items_table.setStyle(TableStyle([
        # Header
        ('BACKGROUND', (0, 0), (-1, 0), PRIMARY),
        ('TEXTCOLOR', (0, 0), (-1, 0), colors.white),
        ('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
        ('FONTSIZE', (0, 0), (-1, -1), 8),
        ('BOTTOMPADDING', (0, 0), (-1, 0), 8),
        ('TOPPADDING', (0, 0), (-1, 0), 8),
        # Rows
        ('ROWBACKGROUNDS', (0, 1), (-1, -1), [colors.white, LIGHT_GREY]),
        ('ALIGN', (3, 0), (-1, -1), 'RIGHT'),
        ('ALIGN', (0, 0), (2, -1), 'LEFT'),
        ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
        ('GRID', (0, 0), (-1, -1), 0.3, MID_GREY),
        ('BOTTOMPADDING', (0, 1), (-1, -1), 5),
        ('TOPPADDING', (0, 1), (-1, -1), 5),
    ]))

    story.append(items_table)
    story.append(Spacer(1, 0.5*cm))

    # ── Totals ────────────────────────────────────────────────────────────
    curr = invoice.currency
    totals_rows = [
        ["", "Sous-total HT:", f"{invoice.subtotal_ht:,.0f} {curr}"],
        ["", "Total TVA:", f"{invoice.total_tax:,.0f} {curr}"],
    ]

    if invoice.discount_amount and invoice.discount_amount > 0:
        totals_rows.append(["", f"Remise ({invoice.discount_percent:.0f}%):", f"-{invoice.discount_amount:,.0f} {curr}"])

    totals_rows.append(["", "TOTAL TTC:", f"{invoice.total_ttc:,.0f} {curr}"])

    if invoice.total_paid > 0:
        totals_rows.append(["", "Déjà payé:", f"-{invoice.total_paid:,.0f} {curr}"])

    totals_rows.append(["", "SOLDE DÛ:", f"{max(0, invoice.balance_due):,.0f} {curr}"])

    totals_table = Table(totals_rows, colWidths=[10*cm, 3.5*cm, 3.5*cm])
    totals_table.setStyle(TableStyle([
        ('ALIGN', (1, 0), (-1, -1), 'RIGHT'),
        ('FONTNAME', (1, 3), (-1, 3), 'Helvetica-Bold'),  # Total TTC row bold
        ('FONTSIZE', (0, 0), (-1, -1), 9),
        ('TEXTCOLOR', (1, 3), (-1, 3), PRIMARY),          # Total TTC highlighted
        ('FONTNAME', (1, -1), (-1, -1), 'Helvetica-Bold'),  # Solde dû bold
        ('TEXTCOLOR', (1, -1), (-1, -1), ACCENT),           # Solde dû in accent
        ('BACKGROUND', (1, -1), (-1, -1), LIGHT_GREY),
        ('LINEABOVE', (1, -2), (-1, -2), 0.5, MID_GREY),
        ('TOPPADDING', (0, 0), (-1, -1), 3),
        ('BOTTOMPADDING', (0, 0), (-1, -1), 3),
    ]))
    story.append(totals_table)

    # ── Receipts / Payments ───────────────────────────────────────────────
    valid_receipts = [r for r in invoice.receipts if r.status.value == "issued"]
    if valid_receipts:
        story.append(Spacer(1, 0.5*cm))
        story.append(HRFlowable(width="100%", thickness=0.5, color=MID_GREY))
        story.append(Spacer(1, 0.3*cm))
        story.append(Paragraph("<b>Paiements enregistrés</b>", s["header"]))
        story.append(Spacer(1, 0.2*cm))

        pmt_data = [["N° Reçu", "Date", "Mode de paiement", "Référence", "Montant"]]
        for r in valid_receipts:
            method_label = PAYMENT_METHOD_LABELS.get(r.payment_method, r.payment_method)
            pmt_data.append([
                r.receipt_number,
                r.payment_date.strftime("%d/%m/%Y %H:%M") if r.payment_date else "-",
                method_label,
                r.payment_reference or "-",
                f"{r.amount:,.0f} {r.currency}",
            ])

        pmt_table = Table(pmt_data, colWidths=[3*cm, 4*cm, 3.5*cm, 3.5*cm, 3*cm])
        pmt_table.setStyle(TableStyle([
            ('BACKGROUND', (0, 0), (-1, 0), colors.lightgrey),
            ('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
            ('FONTSIZE', (0, 0), (-1, -1), 8),
            ('GRID', (0, 0), (-1, -1), 0.3, MID_GREY),
            ('ALIGN', (-1, 0), (-1, -1), 'RIGHT'),
            ('ROWBACKGROUNDS', (0, 1), (-1, -1), [colors.white, LIGHT_GREY]),
            ('BOTTOMPADDING', (0, 0), (-1, -1), 5),
        ]))
        story.append(pmt_table)

    # ── Notes ─────────────────────────────────────────────────────────────
    if invoice.notes:
        story.append(Spacer(1, 0.5*cm))
        story.append(Paragraph(f"<b>Notes:</b> {invoice.notes}", s["header"]))

    if invoice.payment_terms:
        story.append(Spacer(1, 0.2*cm))
        story.append(Paragraph(f"<b>Conditions de paiement:</b> {invoice.payment_terms}", s["header"]))

    # ── Footer ────────────────────────────────────────────────────────────
    story.append(Spacer(1, 1*cm))
    story.append(HRFlowable(width="100%", thickness=0.5, color=MID_GREY))
    story.append(Spacer(1, 0.3*cm))
    story.append(Paragraph(
        "Merci pour votre confiance. Nous espérons vous revoir très prochainement.",
        s["footer"]
    ))
    story.append(Paragraph(
        f"Document généré le {datetime.now().strftime('%d/%m/%Y à %H:%M')} par FiHotelFlow",
        s["footer"]
    ))

    doc.build(story)
    return buffer.getvalue()


def generate_receipt_pdf(receipt, invoice=None) -> bytes:
    """
    Generate a compact payment receipt PDF.

    Args:
        receipt: Receipt model instance
        invoice: Invoice model for context

    Returns:
        PDF bytes
    """
    buffer = BytesIO()
    # Use smaller page (half A4 / A5 like)
    doc = SimpleDocTemplate(
        buffer, pagesize=A4,
        rightMargin=2*cm, leftMargin=2*cm,
        topMargin=1.5*cm, bottomMargin=1.5*cm
    )

    s = _build_styles()
    story = []

    inv = invoice or receipt.invoice

    # ── Header ────────────────────────────────────────────────────────────
    est = inv.establishment if inv and hasattr(inv, 'establishment') else None
    est_name = est.name if est else "FiHotelFlow"
    est_phone = est.phone if est else ""

    story.append(Paragraph(est_name, s["title"]))
    story.append(Paragraph(f"Tél: {est_phone}", s["subtitle"]))
    story.append(HRFlowable(width="100%", thickness=2, color=PRIMARY))
    story.append(Spacer(1, 0.5*cm))
    story.append(Paragraph("REÇU DE PAIEMENT", ParagraphStyle(
        "ReceiptTitle", parent=s["title"], fontSize=18, textColor=ACCENT
    )))
    story.append(Spacer(1, 0.5*cm))

    # ── Details ────────────────────────────────────────────────────────────
    payment_date = receipt.payment_date.strftime("%d/%m/%Y à %H:%M") if receipt.payment_date else datetime.now().strftime("%d/%m/%Y à %H:%M")
    method_label = PAYMENT_METHOD_LABELS.get(receipt.payment_method, receipt.payment_method)
    client_name = ""
    if inv and inv.client:
        client_name = inv.client.full_name
    elif inv:
        client_name = inv.client_name or ""

    details = [
        ["N° Reçu:", receipt.receipt_number],
        ["Date:", payment_date],
        ["Facture N°:", inv.invoice_number if inv else "-"],
        ["Client:", client_name],
        ["Mode de paiement:", method_label],
        ["Référence:", receipt.payment_reference or "-"],
    ]

    details_table = Table(details, colWidths=[5*cm, 12*cm])
    details_table.setStyle(TableStyle([
        ('FONTSIZE', (0, 0), (-1, -1), 10),
        ('FONTNAME', (0, 0), (0, -1), 'Helvetica-Bold'),
        ('BOTTOMPADDING', (0, 0), (-1, -1), 6),
        ('TOPPADDING', (0, 0), (-1, -1), 6),
        ('ROWBACKGROUNDS', (0, 0), (-1, -1), [colors.white, LIGHT_GREY]),
    ]))
    story.append(details_table)
    story.append(Spacer(1, 0.5*cm))

    # ── Amount Box ─────────────────────────────────────────────────────────
    amount_data = [[
        Paragraph("MONTANT REÇU", ParagraphStyle("AmtLabel", fontSize=12, fontName="Helvetica-Bold", textColor=colors.white, alignment=TA_CENTER)),
        Paragraph(f"{receipt.amount:,.0f} {receipt.currency}", ParagraphStyle("AmtVal", fontSize=20, fontName="Helvetica-Bold", textColor=colors.white, alignment=TA_CENTER))
    ]]
    amount_table = Table(amount_data, colWidths=[6*cm, 11*cm])
    amount_table.setStyle(TableStyle([
        ('BACKGROUND', (0, 0), (-1, -1), PRIMARY),
        ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
        ('BOTTOMPADDING', (0, 0), (-1, -1), 12),
        ('TOPPADDING', (0, 0), (-1, -1), 12),
        ('ROUNDEDCORNERS', [5, 5, 5, 5]),
    ]))
    story.append(amount_table)
    story.append(Spacer(1, 0.5*cm))

    # ── Invoice Balance ─────────────────────────────────────────────────────
    if inv:
        balance = max(0, inv.balance_due)
        balance_info = f"Solde restant sur la facture: <b>{balance:,.0f} {inv.currency}</b>"
        story.append(Paragraph(balance_info, s["right"]))

    # ── Notes ──────────────────────────────────────────────────────────────
    if receipt.notes:
        story.append(Spacer(1, 0.3*cm))
        story.append(Paragraph(f"Note: {receipt.notes}", s["header"]))

    # ── Footer ─────────────────────────────────────────────────────────────
    story.append(Spacer(1, 1*cm))
    story.append(HRFlowable(width="100%", thickness=0.5, color=MID_GREY))
    story.append(Spacer(1, 0.3*cm))
    story.append(Paragraph("Merci pour votre paiement!", s["footer"]))
    story.append(Paragraph(
        f"Généré le {datetime.now().strftime('%d/%m/%Y %H:%M')} - FiHotelFlow",
        s["footer"]
    ))

    doc.build(story)
    return buffer.getvalue()


def _status_label(status) -> str:
    labels = {
        "draft": "Brouillon",
        "issued": "Émise",
        "paid": "Payée",
        "partially_paid": "Partiellement payée",
        "overdue": "En retard",
        "cancelled": "Annulée",
        "refunded": "Remboursée",
    }
    val = status.value if hasattr(status, 'value') else str(status)
    return labels.get(val, val)
