"""
thermal_receipt.py
==================
Drop-in replacement for _generate_thermal_receipt_pdf().
Uses fpdf2 only — no WeasyPrint, no heavy deps.

Design decisions
----------------
- 80mm thermal width → 2mm left margin, 4mm right margin → 74mm usable
- Content is left-shifted: MARGIN_L=2, MARGIN_R=4 gives more room on the left
- Courier for all numeric/tabular content (monospace = aligned columns)
- Helvetica for headings, labels, branding (proportional = compact)
- Column layout: ITEM 40mm | QTY 11mm | PRICE 23mm = 74mm total
- Dashed dividers via set_dash_pattern()
- Branded top stripe via filled rect in forest green (#417A52)
- Serial numbers as indented sub-line under item name
- QR code bottom-right, footer text bottom-left

Readability rules
-----------------
- Minimum font size for any readable content: 9pt
- Secondary/meta content (serial, ref, timestamp): 8.5pt + GREY_DARK
- Decorative chrome only (tear-off dashes): 7pt + GREY_LIGHT
- Grey text never used for primary information — BLACK or GREY_DARK only
- Row heights scale with font size throughout

Margin layout
-------------
MARGIN_L = 2mm  (left — shifted in to gain space)
MARGIN_R = 4mm  (right)
USABLE_W = 80 - 2 - 4 = 74mm
Columns: 40 + 11 + 23 = 74mm exactly
"""

from fpdf import FPDF
from datetime import datetime
import tempfile
import os


# ── Constants ─────────────────────────────────────────────────────────────────

PAGE_W   = 80          # mm — standard 80mm thermal roll
MARGIN_L = 2           # mm — left margin (shifted in for extra space)
MARGIN_R = 4           # mm — right margin
USABLE_W = PAGE_W - MARGIN_L - MARGIN_R   # 74mm

# Column widths — must sum exactly to USABLE_W (74mm)
COL_ITEM  = 40         # wider item column; gains 4mm vs old layout
COL_QTY   = 11
COL_PRICE = 23

# Brand colours (RGB)
FOREST      = (65, 122, 82)    # #417A52
FOREST_DARK = (44, 87, 57)     # #2C5739
WHITE       = (255, 255, 255)
BLACK       = (0,   0,   0)
GREY_DARK   = (60,  60,  60)   # served-by, serial, ref, timestamp
GREY_MID    = (90,  90,  90)   # dividers and structural lines only
GREY_LIGHT  = (140, 140, 140)  # decorative chrome only (tear-off dashes)


# ── ThermalPDF ────────────────────────────────────────────────────────────────

class ThermalPDF(FPDF):
    """80mm thermal receipt canvas with left-shifted margins."""

    def __init__(self):
        super().__init__(unit='mm', format=(PAGE_W, 400))
        self.set_margins(MARGIN_L, 0, MARGIN_R)
        self.set_auto_page_break(auto=False)
        self.add_page()

    # ── Drawing helpers ────────────────────────────────────────────────────────

    def solid_line(self, lw=0.25):
        self.set_line_width(lw)
        self.set_draw_color(*GREY_DARK)
        self.line(MARGIN_L, self.get_y(), PAGE_W - MARGIN_R, self.get_y())

    def dashed_line(self):
        self.set_line_width(0.15)
        self.set_draw_color(*GREY_MID)
        self.set_dash_pattern(dash=0.8, gap=0.8)
        self.line(MARGIN_L, self.get_y() + 1, PAGE_W - MARGIN_R, self.get_y() + 1)
        self.set_dash_pattern(dash=0, gap=0)
        self.ln(2)

    def vspace(self, h=2):
        self.ln(h)

    # ── Branding ───────────────────────────────────────────────────────────────

    def stripe(self):
        """3mm forest-green bar across the full page top."""
        self.set_fill_color(*FOREST)
        self.rect(0, 0, PAGE_W, 3, style='F')
        self.set_y(3)
        self.vspace(2)

    def section_label(self, text):
        """Spaced-caps section divider label — left-aligned, dark grey."""
        self.vspace(2)
        self.set_font('Helvetica', 'B', 8.5)
        self.set_text_color(*GREY_DARK)
        self.cell(0, 3.5, text.upper(), ln=True, align='L')
        self.set_text_color(*BLACK)
        self.vspace(1)


# ── Main receipt function ─────────────────────────────────────────────────────

def _generate_thermal_receipt_pdf(sale):
    """
    Generate a professional 80mm thermal receipt PDF.

    Args
    ----
    sale : Sale model instance (Django ORM object)

    Returns
    -------
    bytes -- raw PDF bytes ready to serve or write to disk.
    """

    pdf = ThermalPDF()

    # ── STRIPE ────────────────────────────────────────────────────────────────
    pdf.stripe()

    # ── BUSINESS HEADER ───────────────────────────────────────────────────────
    pdf.set_font('Helvetica', 'B', 13)
    pdf.set_text_color(*BLACK)
    pdf.cell(0, 5, sale.business.name.upper(), ln=True, align='C')

    biz = sale.business
    pdf.set_font('Helvetica', '', 9)
    pdf.set_text_color(*GREY_DARK)

    if getattr(biz, 'email', None):
        pdf.cell(0, 4, biz.email, ln=True, align='C')
    if getattr(biz, 'address_line1', None):
        for line in biz.address_line1.split('\n')[:2]:
            pdf.cell(0, 4, line.strip(), ln=True, align='C')
    if getattr(biz, 'phone_number', None):
        pdf.cell(0, 4, f"Tel: {biz.phone_number}", ln=True, align='C')
    if getattr(biz, 'tax_id', None):
        pdf.cell(0, 4, f"PIN: {biz.tax_id}", ln=True, align='C')

    pdf.set_text_color(*BLACK)
    pdf.vspace(2)
    pdf.solid_line()
    pdf.vspace(2)

    # ── RECEIPT META ──────────────────────────────────────────────────────────
    pdf.set_font('Helvetica', '', 9)
    pdf.cell(USABLE_W * 0.5, 4, sale.sale_date.strftime('%d/%m/%Y'), align='L')
    pdf.cell(USABLE_W * 0.5, 4, 'SALES RECEIPT', align='R', ln=True)

    pdf.set_font('Helvetica', '', 9)
    pdf.cell(USABLE_W * 0.5, 4, sale.sale_date.strftime('%I:%M %p').upper(), align='L')
    pdf.set_font('Helvetica', 'B', 9)
    pdf.cell(USABLE_W * 0.5, 4, f"#{sale.sale_number}", align='R', ln=True)

    pdf.vspace(2)

    # ── CUSTOMER ──────────────────────────────────────────────────────────────
    if sale.customer:
        pdf.set_font('Helvetica', 'B', 9.5)
        pdf.set_text_color(*BLACK)
        name_line = sale.customer.name.upper()
        if getattr(sale.customer, 'phone', None):
            name_line += f"  {sale.customer.phone}"
        pdf.cell(0, 4.5, name_line, ln=True)

    # ── SERVED BY ─────────────────────────────────────────────────────────────
    if getattr(sale, 'salesperson', None):
        pdf.vspace(1)
        pdf.set_font('Helvetica', '', 9)
        pdf.set_text_color(*GREY_DARK)
        pdf.cell(0, 4, f"Served by: {sale.salesperson.get_full_name()}", ln=True, align='L')

    pdf.set_text_color(*BLACK)
    pdf.vspace(2)
    pdf.dashed_line()
    pdf.vspace(2)

    # ── ITEMS TABLE HEADER ────────────────────────────────────────────────────
    pdf.set_font('Helvetica', 'B', 9)
    pdf.set_text_color(*GREY_DARK)
    pdf.cell(COL_ITEM,  4, 'ITEM',   align='L')
    pdf.cell(COL_QTY,   4, 'QTY',   align='C')
    pdf.cell(COL_PRICE, 4, 'AMOUNT', align='R', ln=True)
    pdf.set_text_color(*BLACK)
    pdf.vspace(1)
    pdf.dashed_line()
    pdf.vspace(2)

    # ── ITEMS ─────────────────────────────────────────────────────────────────
    for sale_item in sale.items.all():
        # Resolve the underlying inventory/accessory object for serial number
        actual = None
        if sale_item.item_type == 'inventory_item' and sale_item.inventory_item:
            actual = sale_item.inventory_item
        elif sale_item.item_type == 'accessory_item' and sale_item.accessory_item:
            actual = sale_item.accessory_item

        item_name = sale_item.item_name.upper()
        serial = (
            actual.serial_number
            if actual and getattr(actual, 'serial_number', None)
            else None
        )

        # ── Word-wrap item name into COL_ITEM width ────────────────────────
        # Font must match the render font below for accurate measurement
        pdf.set_font('Helvetica', 'B', 9)
        words   = item_name.split()
        lines   = []
        current = ''
        for word in words:
            test = (current + ' ' + word).strip()
            if pdf.get_string_width(test) <= COL_ITEM - 0.5:
                current = test
            else:
                if current:
                    lines.append(current)
                current = word
        if current:
            lines.append(current)

        # First line: name | qty | unit price
        pdf.set_font('Helvetica', 'B', 9)
        pdf.cell(COL_ITEM,  4.5, lines[0], align='L')
        pdf.set_font('Courier', '', 9)
        pdf.cell(COL_QTY,   4.5, str(sale_item.quantity), align='C')
        pdf.cell(COL_PRICE, 4.5, f"KES {float(sale_item.unit_price):,.2f}", align='R', ln=True)

        # Overflow name lines (rare for short names)
        if len(lines) > 1:
            pdf.set_font('Helvetica', '', 9)
            pdf.set_text_color(*BLACK)
            for extra in lines[1:]:
                pdf.cell(COL_ITEM, 4, extra, align='L', ln=True)

        # Serial number sub-line
        if serial:
            pdf.set_font('Helvetica', '', 8.5)
            pdf.set_text_color(*GREY_DARK)
            pdf.cell(0, 3.5, f"  S/N: {serial}", align='L', ln=True)
            pdf.set_text_color(*BLACK)

        pdf.vspace(1.5)

    # ── TOTALS ────────────────────────────────────────────────────────────────
    pdf.vspace(1)
    pdf.dashed_line()
    pdf.vspace(2)

    def total_row(label, value, bold=False, large=False):
        size   = 11 if large else 9
        style  = 'B' if bold else ''
        gutter = 3
        row_h  = size * 0.45 + 1.5
        pdf.set_font('Helvetica', style, size)
        pdf.cell(COL_ITEM + COL_QTY - gutter, row_h, label, align='R')
        pdf.cell(gutter, row_h, '')
        pdf.set_font('Courier', style, size)
        pdf.cell(COL_PRICE, row_h, value, align='R', ln=True)

    total_row('Subtotal   ', f"KES {float(sale.subtotal):,.2f}")

    if sale.discount_amount > 0:
        total_row('Discount', f"-KES {float(sale.discount_amount):,.2f}")

    if sale.tax_amount > 0:
        total_row('VAT (16%)', f"KES {float(sale.tax_amount):,.2f}")

    # Short rule above grand total (totals column only)
    pdf.vspace(1)
    pdf.set_line_width(0.2)
    pdf.set_draw_color(*GREY_DARK)
    line_x = MARGIN_L + COL_ITEM + COL_QTY
    pdf.line(line_x, pdf.get_y(), PAGE_W - MARGIN_R, pdf.get_y())
    pdf.vspace(1)

    total_row('TOTAL     ', f"KES {float(sale.total_amount):,.2f}", bold=True, large=True)

    pdf.vspace(2)
    pdf.solid_line()
    pdf.vspace(3)

    # ── PAYMENT DETAILS ───────────────────────────────────────────────────────
    if sale.payments.exists():
        gutter = 3
        for payment in sale.payments.all():
            method = payment.payment_mode.get_name_display().upper()
            pdf.set_font('Helvetica', '', 9)
            pdf.cell(COL_ITEM + COL_QTY - gutter, 4.5, method, align='R')
            pdf.cell(gutter, 4.5, '')
            pdf.set_font('Courier', '', 9)
            pdf.cell(COL_PRICE, 4.5, f"KES {float(payment.amount):,.2f}", align='R', ln=True)

            if payment.reference_number:
                pdf.set_font('Helvetica', '', 8.5)
                pdf.set_text_color(*GREY_DARK)
                pdf.cell(0, 3.5, f"Ref: {payment.reference_number}", align='R', ln=True)
                pdf.set_text_color(*BLACK)

        total_paid = sum(float(p.amount) for p in sale.payments.all())
        change     = total_paid - float(sale.total_amount)
        if change > 0.005:
            pdf.vspace(1)
            pdf.set_font('Helvetica', 'B', 9)
            pdf.cell(COL_ITEM + COL_QTY - gutter, 4.5, 'CHANGE', align='R')
            pdf.cell(gutter, 4.5, '')
            pdf.set_font('Courier', 'B', 9)
            pdf.cell(COL_PRICE, 4.5, f"KES {change:,.2f}", align='R', ln=True)

        pdf.vspace(2)

    pdf.dashed_line()
    pdf.vspace(2)

    # ── WARRANTY & POLICY ─────────────────────────────────────────────────────
    pdf.set_font('Helvetica', 'B', 9)
    pdf.set_text_color(*BLACK)
    pdf.cell(0, 4, 'WARRANTY & POLICY', ln=True)
    pdf.vspace(1)

    pdf.set_font('Helvetica', '', 9)
    pdf.set_text_color(*BLACK)
    notes = [
        "I.   New equipment - 12 months warranty",
        "II.  EX-UK/Refurbished - 6 months warranty",
        "III. Adapters, RAM, storage & software excluded",
        "IV.  Exchanges for defective items within warranty only",
        "V.   Returns accepted within 7 business days",
    ]
    for note in notes:
        pdf.cell(0, 4, note, ln=True)

    pdf.set_text_color(*BLACK)
    pdf.vspace(2)
    pdf.solid_line()
    pdf.vspace(3)

    # ── FOOTER: branding left | QR right ─────────────────────────────────────
    footer_y = pdf.get_y()
    qr_size  = 16        # mm
    text_w   = USABLE_W - qr_size - 2
    qr_path  = None

    # Generate QR code
    try:
        import qrcode
        qr = qrcode.QRCode(
            version=1,
            error_correction=qrcode.constants.ERROR_CORRECT_M,
            box_size=4,
            border=1,
        )
        qr.add_data('https://www.trato.binbyte.co.ke')
        qr.make(fit=True)
        qr_img = qr.make_image(fill_color='black', back_color='white')
        with tempfile.NamedTemporaryFile(delete=False, suffix='.png') as tmp:
            qr_img.save(tmp.name, format='PNG')
            qr_path = tmp.name
    except Exception:
        pass   # QR is non-critical; continue without it

    # Branding text (left column)
    pdf.set_font('Helvetica', 'B', 9)
    pdf.set_text_color(*BLACK)
    pdf.cell(text_w, 4, sale.business.name.upper(), ln=True)

    pdf.set_font('Helvetica', 'B', 8.5)
    pdf.set_text_color(*FOREST)
    pdf.cell(text_w, 4, 'Powered by Trato - BinByte', ln=True)

    pdf.set_font('Helvetica', '', 8.5)
    pdf.set_text_color(*GREY_DARK)
    pdf.cell(text_w, 4, 'trato.binbyte.co.ke', ln=True)
    pdf.cell(text_w, 4, '+254 798 969 800', ln=True)
    pdf.set_text_color(*BLACK)

    # QR code (right column, anchored to footer_y)
    if qr_path:
        qr_x = PAGE_W - MARGIN_R - qr_size
        try:
            pdf.image(qr_path, x=qr_x, y=footer_y, w=qr_size, h=qr_size)
        except Exception:
            pass
        finally:
            try:
                os.unlink(qr_path)
            except Exception:
                pass

    # Advance cursor past whichever column is taller
    footer_end_y = max(pdf.get_y(), footer_y + qr_size)
    pdf.set_y(footer_end_y)
    pdf.vspace(3)

    # ── THANK YOU ─────────────────────────────────────────────────────────────
    pdf.solid_line(lw=0.3)
    pdf.vspace(3)

    pdf.set_font('Helvetica', 'B', 9.5)
    pdf.set_text_color(*BLACK)
    pdf.cell(0, 4.5, 'THANK YOU FOR YOUR PURCHASE!', ln=True, align='C')

    pdf.vspace(1)
    pdf.set_font('Helvetica', '', 8.5)
    pdf.set_text_color(*GREY_DARK)
    pdf.cell(0, 4, f"Printed: {datetime.now().strftime('%d/%m/%Y %I:%M %p')}", ln=True, align='C')
    pdf.set_text_color(*BLACK)

    pdf.vspace(3)

    # ── TEAR-OFF DASHES ───────────────────────────────────────────────────────
    # Decorative only — GREY_LIGHT + 7pt intentional
    pdf.set_font('Helvetica', '', 7)
    pdf.set_text_color(*GREY_LIGHT)
    pdf.cell(0, 3, '- ' * 19, ln=True, align='C')
    pdf.set_text_color(*BLACK)

    pdf.vspace(2)

    # ── OUTPUT ────────────────────────────────────────────────────────────────
    pdf_output = pdf.output(dest='S')
    if isinstance(pdf_output, (bytes, bytearray)):
        return bytes(pdf_output)
    return pdf_output.encode('latin-1')