"""Order confirmation PDF generation (reportlab)."""
from __future__ import annotations

from datetime import datetime
from io import BytesIO

from app.models.client_access import ClientAccount
from app.models.ordering import Order


class OrderPdfUnavailableError(RuntimeError):
    pass


def _fmt_money(value: float | None) -> str:
    return "Quote" if value is None else f"${value:,.2f}"


def build_order_confirmation_pdf(order: Order, customer: ClientAccount | None) -> bytes:
    try:
        from reportlab.lib import colors
        from reportlab.lib.pagesizes import A4
        from reportlab.pdfgen import canvas
    except ModuleNotFoundError as exc:  # pragma: no cover
        raise OrderPdfUnavailableError(
            "PDF generation is unavailable because 'reportlab' is not installed."
        ) from exc

    buffer = BytesIO()
    page_width, page_height = A4
    pdf = canvas.Canvas(buffer, pagesize=A4)
    margin = 40
    y = page_height - margin

    pdf.setFont("Helvetica-Bold", 18)
    pdf.drawString(margin, y, "Order Confirmation")
    y -= 24

    pdf.setFont("Helvetica", 10)
    order_ref = order.order_number or f"#{order.id}"
    pdf.drawString(margin, y, f"Order: {order_ref}")
    pdf.drawRightString(page_width - margin, y, datetime.utcnow().strftime("%d %b %Y %H:%M UTC"))
    y -= 14
    pdf.drawString(margin, y, f"Customer: {customer.name if customer else order.client_account_id}")
    y -= 14
    pdf.drawString(margin, y, f"Status: {order.status.replace('_', ' ').title()}")
    y -= 14
    if order.purchase_order_number:
        pdf.drawString(margin, y, f"PO Number: {order.purchase_order_number}")
        y -= 14
    pdf.drawString(margin, y, f"Fulfilment: {order.fulfilment_method.title()}")
    y -= 14
    if order.requested_delivery_date:
        pdf.drawString(margin, y, f"Requested date: {order.requested_delivery_date.strftime('%d %b %Y')}")
        y -= 14
    y -= 6

    # Table header
    pdf.setFont("Helvetica-Bold", 9)
    pdf.setFillColor(colors.HexColor("#22362d"))
    pdf.drawString(margin, y, "Product")
    pdf.drawString(margin + 220, y, "SKU")
    pdf.drawRightString(margin + 330, y, "Qty")
    pdf.drawRightString(margin + 420, y, "Unit (ex GST)")
    pdf.drawRightString(page_width - margin, y, "Line total")
    y -= 6
    pdf.setStrokeColor(colors.HexColor("#cccccc"))
    pdf.line(margin, y, page_width - margin, y)
    y -= 14

    pdf.setFont("Helvetica", 9)
    pdf.setFillColor(colors.black)
    for line in order.lines:
        if y < margin + 60:
            pdf.showPage()
            y = page_height - margin
            pdf.setFont("Helvetica", 9)
        unit = line.admin_override_price if line.admin_override_price is not None else line.unit_price
        line_total = None if unit is None else round(unit * line.quantity, 2)
        pdf.drawString(margin, y, (line.product_name or "")[:38])
        pdf.drawString(margin + 220, y, (line.product_sku or "")[:16])
        pdf.drawRightString(margin + 330, y, f"{line.quantity:g}")
        pdf.drawRightString(margin + 420, y, _fmt_money(unit))
        pdf.drawRightString(page_width - margin, y, _fmt_money(line_total))
        y -= 14

    y -= 4
    pdf.line(margin, y, page_width - margin, y)
    y -= 16
    pdf.setFont("Helvetica-Bold", 10)
    pdf.drawRightString(margin + 420, y, "Subtotal (ex GST)")
    pdf.drawRightString(page_width - margin, y, _fmt_money(order.subtotal_ex_gst))
    y -= 20

    if order.requires_quote:
        pdf.setFont("Helvetica-Oblique", 9)
        pdf.setFillColor(colors.HexColor("#8a5a00"))
        pdf.drawString(margin, y, "This order contains quote-only items. Final pricing will be confirmed by our team.")
        y -= 14

    if order.delivery_notes:
        pdf.setFont("Helvetica", 9)
        pdf.setFillColor(colors.black)
        pdf.drawString(margin, y, f"Notes: {order.delivery_notes[:90]}")

    pdf.setFont("Helvetica-Oblique", 8)
    pdf.setFillColor(colors.HexColor("#888888"))
    pdf.drawString(margin, margin - 12, "Prices exclude GST. This is an order confirmation, not a tax invoice.")

    pdf.showPage()
    pdf.save()
    return buffer.getvalue()
