import { jsPDF } from 'jspdf'
import type { InvoiceTemplateConfig } from './invoiceTemplates'
import type { Invoice } from '../stores/invoices'
import type { Client } from '../stores/clients'
import type { InvoiceItem } from './invoicePdf'
import { formatCurrency, formatDate } from './locale'

// ---------------------------------------------------------------------------
// Exported types
// ---------------------------------------------------------------------------

export interface BusinessInfo {
  name: string
  address: string
  email: string
  phone: string
  logo: string // base64 data URL or empty string
}

// ---------------------------------------------------------------------------
// Shared helpers
// ---------------------------------------------------------------------------

function hexToRgb(hex: string): [number, number, number] {
  const h = hex.replace('#', '')
  return [
    parseInt(h.substring(0, 2), 16),
    parseInt(h.substring(2, 4), 16),
    parseInt(h.substring(4, 6), 16),
  ]
}

function setText(doc: jsPDF, hex: string) {
  const [r, g, b] = hexToRgb(hex)
  doc.setTextColor(r, g, b)
}

function setFill(doc: jsPDF, hex: string) {
  const [r, g, b] = hexToRgb(hex)
  doc.setFillColor(r, g, b)
}

function setDraw(doc: jsPDF, hex: string) {
  const [r, g, b] = hexToRgb(hex)
  doc.setDrawColor(r, g, b)
}

function truncateDesc(doc: jsPDF, text: string, maxWidth: number): string {
  if (doc.getTextWidth(text) <= maxWidth) return text
  while (doc.getTextWidth(text + '...') > maxWidth && text.length > 0) {
    text = text.slice(0, -1)
  }
  return text + '...'
}

function drawLogo(doc: jsPDF, logo: string, x: number, y: number, maxH: number): number {
  if (!logo) return 0
  try {
    doc.addImage(logo, 'PNG', x, y, 0, maxH)
    return maxH + 2
  } catch {
    return 0
  }
}

// ---------------------------------------------------------------------------
// Shared table column geometry
// ---------------------------------------------------------------------------

type ColLayout = { colX: number[]; colW: number[] }

function tableLayout(startX: number, contentW: number): ColLayout {
  const descW = contentW * 0.48
  const qtyW = contentW * 0.12
  const rateW = contentW * 0.20
  const amtW = contentW * 0.20
  return {
    colW: [descW, qtyW, rateW, amtW],
    colX: [startX, startX + descW, startX + descW + qtyW, startX + descW + qtyW + rateW],
  }
}

// Tracked uppercase helper
function trackedText(doc: jsPDF, str: string, x: number, y: number, opts?: { align?: 'left' | 'right' | 'center' }) {
  doc.setCharSpace(0.3)
  doc.text(str, x, y, opts)
  doc.setCharSpace(0)
}

// Draw header row text (uppercase, tracked)
function drawHeaderText(
  doc: jsPDF, layout: ColLayout, y: number, rowH: number, colorHex: string, padX: number,
) {
  doc.setFont('helvetica', 'bold')
  doc.setFontSize(9)
  setText(doc, colorHex)
  const textY = y + rowH * 0.65
  trackedText(doc, 'DESCRIPTION', layout.colX[0] + padX, textY)
  trackedText(doc, 'QTY', layout.colX[1] + padX, textY)
  doc.text('RATE', layout.colX[2] + layout.colW[2] - padX, textY, { align: 'right' })
  doc.text('AMOUNT', layout.colX[3] + layout.colW[3] - padX, textY, { align: 'right' })
  doc.setCharSpace(0)
}

// Draw a single item row (returns new y)
function drawItemRow(
  doc: jsPDF, item: InvoiceItem, layout: ColLayout, y: number, rowH: number,
  textColor: string, padX: number,
): number {
  doc.setFont('helvetica', 'normal')
  doc.setFontSize(10)
  setText(doc, textColor)
  const textY = y + rowH * 0.65
  const desc = truncateDesc(doc, item.description, layout.colW[0] - padX * 2)
  doc.text(desc, layout.colX[0] + padX, textY)
  doc.text(String(item.quantity), layout.colX[1] + padX, textY)
  doc.text(formatCurrency(item.rate), layout.colX[2] + layout.colW[2] - padX, textY, { align: 'right' })
  doc.text(formatCurrency(item.amount), layout.colX[3] + layout.colW[3] - padX, textY, { align: 'right' })
  return y + rowH
}

// Draw totals block (returns new y)
function drawTotals(
  doc: jsPDF, invoice: Invoice, rightX: number, y: number,
  textColor: string, totalColor: string, totalSize: number,
): number {
  doc.setFont('helvetica', 'normal')
  doc.setFontSize(10)
  setText(doc, textColor)
  doc.text(`Subtotal`, rightX - 50, y)
  doc.text(formatCurrency(invoice.subtotal), rightX, y, { align: 'right' })
  y += 7
  if (invoice.tax_rate > 0) {
    doc.text(`Tax (${invoice.tax_rate}%)`, rightX - 50, y)
    doc.text(formatCurrency(invoice.tax_amount), rightX, y, { align: 'right' })
    y += 7
  }
  if (invoice.discount > 0) {
    doc.text(`Discount`, rightX - 50, y)
    doc.text(`-${formatCurrency(invoice.discount)}`, rightX, y, { align: 'right' })
    y += 7
  }
  y += 3
  doc.setFont('helvetica', 'bold')
  doc.setFontSize(totalSize)
  setText(doc, totalColor)
  doc.text('TOTAL', rightX - 50, y)
  doc.text(formatCurrency(invoice.total), rightX, y, { align: 'right' })
  return y
}

// Draw notes section (returns new y)
function drawNotes(doc: jsPDF, invoice: Invoice, margin: number, contentW: number, y: number, textColor: string): number {
  if (!invoice.notes) return y
  if (y > 260) { doc.addPage(); y = 20 }
  doc.setFont('helvetica', 'normal')
  doc.setFontSize(8)
  setText(doc, textColor)
  doc.text('Notes:', margin, y)
  y += 5
  const noteLines = doc.splitTextToSize(invoice.notes, contentW)
  doc.text(noteLines, margin, y)
  y += noteLines.length * 4
  return y
}

// Draw From column (business info)
function drawFromColumn(doc: jsPDF, biz: BusinessInfo, x: number, y: number, textColor: string, labelColor: string, maxW: number): number {
  doc.setFont('helvetica', 'bold')
  doc.setFontSize(11)
  setText(doc, labelColor)
  trackedText(doc, 'FROM', x, y)
  y += 6
  doc.setFont('helvetica', 'bold')
  doc.setFontSize(10)
  setText(doc, textColor)
  if (biz.name) { doc.text(biz.name, x, y); y += 5 }
  doc.setFont('helvetica', 'normal')
  doc.setFontSize(10)
  if (biz.address) {
    const lines = doc.splitTextToSize(biz.address, maxW)
    doc.text(lines, x, y)
    y += lines.length * 5
  }
  if (biz.email) { doc.text(biz.email, x, y); y += 5 }
  if (biz.phone) { doc.text(biz.phone, x, y); y += 5 }
  return y
}

// Draw To column (client info)
function drawToColumn(doc: jsPDF, client: Client, x: number, y: number, textColor: string, labelColor: string, maxW: number): number {
  doc.setFont('helvetica', 'bold')
  doc.setFontSize(11)
  setText(doc, labelColor)
  trackedText(doc, 'TO', x, y)
  y += 6
  doc.setFont('helvetica', 'bold')
  doc.setFontSize(10)
  setText(doc, textColor)
  if (client.name) { doc.text(client.name, x, y); y += 5 }
  doc.setFont('helvetica', 'normal')
  doc.setFontSize(10)
  if (client.email) { doc.text(client.email, x, y); y += 5 }
  if (client.address) {
    const lines = doc.splitTextToSize(client.address, maxW)
    doc.text(lines, x, y)
    y += lines.length * 5
  }
  return y
}

// Page-break guard (returns true if page was added)
function pageBreak(doc: jsPDF, y: number, threshold: number = 262): boolean {
  if (y > threshold) {
    doc.addPage()
    return true
  }
  return false
}


// ===========================================================================
// 1. CLEAN - Swiss minimalism, single blue accent
// ===========================================================================

function renderClean(
  config: InvoiceTemplateConfig,
  invoice: Invoice,
  client: Client,
  items: InvoiceItem[],
  biz: BusinessInfo,
): jsPDF {
  const doc = new jsPDF({ unit: 'mm', format: 'a4' })
  const margin = 20
  const pageW = 210
  const contentW = pageW - margin * 2
  const c = config.colors

  // --- Header: logo + biz name ---
  let y = 20
  const logoH = drawLogo(doc, biz.logo, margin, y, 16)
  y += logoH

  doc.setFont('helvetica', 'bold')
  doc.setFontSize(16)
  setText(doc, c.primary)
  doc.text(biz.name || '', margin, y)
  y += 6
  doc.setFont('helvetica', 'normal')
  doc.setFontSize(10)
  setText(doc, c.bodyText)
  if (biz.address) { doc.text(biz.address, margin, y); y += 5 }
  if (biz.email) { doc.text(biz.email, margin, y); y += 5 }
  if (biz.phone) { doc.text(biz.phone, margin, y); y += 5 }

  // --- INVOICE title + accent line ---
  y += 4
  doc.setFont('helvetica', 'bold')
  doc.setFontSize(28)
  setText(doc, c.primary)
  doc.text('INVOICE', margin, y)
  y += 3
  // 30% width accent line in secondary color
  setFill(doc, c.secondary)
  doc.rect(margin, y, contentW * 0.3, 0.8, 'F')
  y += 8

  // --- Invoice meta ---
  doc.setFont('helvetica', 'normal')
  doc.setFontSize(10)
  setText(doc, c.bodyText)
  doc.text(`# ${invoice.invoice_number}`, margin, y)
  doc.text(`Date: ${formatDate(invoice.date)}`, margin + 50, y)
  if (invoice.due_date) {
    doc.text(`Due: ${formatDate(invoice.due_date)}`, margin + 105, y)
  }
  y += 10

  // --- From / To columns ---
  const fromEndY = drawFromColumn(doc, biz, margin, y, c.bodyText, c.primary, 70)
  const toEndY = drawToColumn(doc, client, pageW / 2 + 5, y, c.bodyText, c.primary, 70)
  y = Math.max(fromEndY, toEndY) + 10

  // --- Table ---
  const layout = tableLayout(margin, contentW)
  const rowH = 9
  const padX = 4

  // Header bg
  setFill(doc, c.tableHeaderBg)
  doc.rect(margin, y, contentW, rowH, 'F')
  drawHeaderText(doc, layout, y, rowH, c.tableHeaderText, padX)
  y += rowH

  // Rows
  for (const item of items) {
    if (pageBreak(doc, y)) y = 20
    // Thin bottom border
    setDraw(doc, c.tableBorder)
    doc.setLineWidth(0.3)
    doc.line(margin, y + rowH, margin + contentW, y + rowH)
    y = drawItemRow(doc, item, layout, y, rowH, c.bodyText, padX)
  }

  // --- Totals ---
  y += 10
  const totalRightX = margin + contentW
  y = drawTotals(doc, invoice, totalRightX, y, c.bodyText, c.secondary, 18)

  // --- Notes ---
  y += 12
  drawNotes(doc, invoice, margin, contentW, y, c.bodyText)

  return doc
}


// ===========================================================================
// 2. PROFESSIONAL - Navy header band, corporate polish
// ===========================================================================

function renderProfessional(
  config: InvoiceTemplateConfig,
  invoice: Invoice,
  client: Client,
  items: InvoiceItem[],
  biz: BusinessInfo,
): jsPDF {
  const doc = new jsPDF({ unit: 'mm', format: 'a4' })
  const margin = 20
  const pageW = 210
  const contentW = pageW - margin * 2
  const c = config.colors

  // --- Full-width navy header rect ---
  setFill(doc, c.headerBg)
  doc.rect(0, 0, 210, 50, 'F')

  // "INVOICE" white inside
  doc.setFont('helvetica', 'bold')
  doc.setFontSize(28)
  setText(doc, c.headerText)
  doc.text('INVOICE', margin, 22)

  // Biz name white right side
  doc.setFontSize(14)
  doc.text(biz.name || '', pageW - margin, 20, { align: 'right' })

  // Invoice meta white inside band
  doc.setFont('helvetica', 'normal')
  doc.setFontSize(10)
  doc.text(`# ${invoice.invoice_number}`, margin, 32)
  doc.text(`Date: ${formatDate(invoice.date)}`, margin, 38)
  if (invoice.due_date) {
    doc.text(`Due: ${formatDate(invoice.due_date)}`, margin, 44)
  }

  // Biz details right side in header
  doc.setFontSize(9)
  let bizY = 28
  if (biz.address) { doc.text(biz.address, pageW - margin, bizY, { align: 'right' }); bizY += 5 }
  if (biz.email) { doc.text(biz.email, pageW - margin, bizY, { align: 'right' }); bizY += 5 }
  if (biz.phone) { doc.text(biz.phone, pageW - margin, bizY, { align: 'right' }); bizY += 5 }

  // --- From / To ---
  let y = 60
  const fromEndY = drawFromColumn(doc, biz, margin, y, c.bodyText, c.primary, 70)
  const toEndY = drawToColumn(doc, client, pageW / 2 + 5, y, c.bodyText, c.primary, 70)
  y = Math.max(fromEndY, toEndY) + 10

  // --- Table ---
  const layout = tableLayout(margin, contentW)
  const rowH = 9
  const padX = 4

  // Navy header row
  setFill(doc, c.tableHeaderBg)
  doc.rect(margin, y, contentW, rowH, 'F')
  drawHeaderText(doc, layout, y, rowH, c.tableHeaderText, padX)
  y += rowH

  // Rows with gray zebra
  for (let i = 0; i < items.length; i++) {
    if (pageBreak(doc, y)) y = 20
    if (i % 2 === 1) {
      setFill(doc, c.tableRowAlt)
      doc.rect(margin, y, contentW, rowH, 'F')
    }
    y = drawItemRow(doc, items[i], layout, y, rowH, c.bodyText, padX)
  }

  // --- Totals ---
  y += 10
  y = drawTotals(doc, invoice, margin + contentW, y, c.bodyText, c.totalHighlight, 18)

  // --- Notes ---
  y += 12
  drawNotes(doc, invoice, margin, contentW, y, c.bodyText)

  return doc
}


// ===========================================================================
// 3. BOLD - Large indigo block with oversized typography
// ===========================================================================

function renderBold(
  config: InvoiceTemplateConfig,
  invoice: Invoice,
  client: Client,
  items: InvoiceItem[],
  biz: BusinessInfo,
): jsPDF {
  const doc = new jsPDF({ unit: 'mm', format: 'a4' })
  const margin = 20
  const pageW = 210
  const contentW = pageW - margin * 2
  const c = config.colors

  // --- Large indigo rect ---
  setFill(doc, c.headerBg)
  doc.rect(0, 0, 115, 50, 'F')

  // "INVOICE" 32pt white inside block
  doc.setFont('helvetica', 'bold')
  doc.setFontSize(32)
  setText(doc, c.headerText)
  doc.text('INVOICE', margin, 25)

  // Invoice # white inside block
  doc.setFont('helvetica', 'normal')
  doc.setFontSize(11)
  doc.text(`# ${invoice.invoice_number}`, margin, 37)

  // Biz info outside block to the right
  let bizY = 14
  doc.setFont('helvetica', 'bold')
  doc.setFontSize(14)
  setText(doc, c.bodyText)
  doc.text(biz.name || '', 125, bizY)
  bizY += 6
  doc.setFont('helvetica', 'normal')
  doc.setFontSize(10)
  if (biz.address) { doc.text(biz.address, 125, bizY); bizY += 5 }
  if (biz.email) { doc.text(biz.email, 125, bizY); bizY += 5 }
  if (biz.phone) { doc.text(biz.phone, 125, bizY); bizY += 5 }

  // Date and due date outside block
  setText(doc, c.bodyText)
  doc.setFontSize(10)
  doc.text(`Date: ${formatDate(invoice.date)}`, 125, bizY)
  bizY += 5
  if (invoice.due_date) {
    doc.setFont('helvetica', 'bold')
    doc.setFontSize(12)
    setText(doc, c.primary)
    doc.text(`Due: ${formatDate(invoice.due_date)}`, 125, bizY)
  }

  // --- FROM / TO with tracked labels ---
  let y = 60
  const fromEndY = drawFromColumn(doc, biz, margin, y, c.bodyText, c.primary, 70)
  const toEndY = drawToColumn(doc, client, pageW / 2 + 5, y, c.bodyText, c.primary, 70)
  y = Math.max(fromEndY, toEndY) + 10

  // --- Table ---
  const layout = tableLayout(margin, contentW)
  const rowH = 10
  const padX = 4

  // Indigo header row
  setFill(doc, c.tableHeaderBg)
  doc.rect(margin, y, contentW, rowH, 'F')
  drawHeaderText(doc, layout, y, rowH, c.tableHeaderText, padX)
  y += rowH

  // Rows - no borders, no stripes, generous height
  for (const item of items) {
    if (pageBreak(doc, y)) y = 20
    y = drawItemRow(doc, item, layout, y, rowH, c.bodyText, padX)
  }

  // --- Totals ---
  y += 10
  y = drawTotals(doc, invoice, margin + contentW, y, c.bodyText, c.totalHighlight, 18)

  // --- Notes ---
  y += 12
  drawNotes(doc, invoice, margin, contentW, y, c.bodyText)

  return doc
}


// ===========================================================================
// 4. MINIMAL - Pure monochrome, everything centered
// ===========================================================================

function renderMinimal(
  config: InvoiceTemplateConfig,
  invoice: Invoice,
  client: Client,
  items: InvoiceItem[],
  biz: BusinessInfo,
): jsPDF {
  const doc = new jsPDF({ unit: 'mm', format: 'a4' })
  const margin = 20
  const pageW = 210
  const contentW = pageW - margin * 2
  const cx = pageW / 2
  const c = config.colors

  // --- "INVOICE" 28pt centered charcoal ---
  let y = 28
  doc.setFont('helvetica', 'bold')
  doc.setFontSize(28)
  setText(doc, c.primary)
  doc.text('INVOICE', cx, y, { align: 'center' })
  y += 6

  // Biz name centered
  doc.setFontSize(14)
  setText(doc, c.headerText)
  doc.text(biz.name || '', cx, y, { align: 'center' })
  y += 5

  // Thin rule
  setDraw(doc, c.tableBorder)
  doc.setLineWidth(0.3)
  doc.line(margin + 20, y, pageW - margin - 20, y)
  y += 6

  // Biz details centered
  doc.setFont('helvetica', 'normal')
  doc.setFontSize(10)
  setText(doc, c.bodyText)
  if (biz.address) { doc.text(biz.address, cx, y, { align: 'center' }); y += 5 }
  if (biz.email) { doc.text(biz.email, cx, y, { align: 'center' }); y += 5 }
  if (biz.phone) { doc.text(biz.phone, cx, y, { align: 'center' }); y += 5 }

  // Invoice meta centered
  y += 2
  doc.text(`Invoice # ${invoice.invoice_number}  |  ${formatDate(invoice.date)}${invoice.due_date ? '  |  Due: ' + formatDate(invoice.due_date) : ''}`, cx, y, { align: 'center' })
  y += 4

  // Thin rule
  doc.line(margin + 20, y, pageW - margin - 20, y)
  y += 8

  // --- From / To centered columns ---
  const fromEndY = drawFromColumn(doc, biz, margin, y, c.bodyText, c.primary, 70)
  const toEndY = drawToColumn(doc, client, pageW / 2 + 5, y, c.bodyText, c.primary, 70)
  y = Math.max(fromEndY, toEndY) + 10

  // --- Table: no backgrounds, header bold only ---
  const layout = tableLayout(margin, contentW)
  const rowH = 9
  const padX = 4

  // Header text only (no bg)
  drawHeaderText(doc, layout, y, rowH, c.primary, padX)
  y += rowH

  // Rows - whitespace separation only
  for (const item of items) {
    if (pageBreak(doc, y)) y = 20
    y = drawItemRow(doc, item, layout, y, rowH, c.bodyText, padX)
  }

  // --- Totals centered-right ---
  y += 10
  // Centered total
  doc.setFont('helvetica', 'bold')
  doc.setFontSize(10)
  setText(doc, c.bodyText)
  doc.text(`Subtotal: ${formatCurrency(invoice.subtotal)}`, cx, y, { align: 'center' })
  y += 7
  if (invoice.tax_rate > 0) {
    doc.setFont('helvetica', 'normal')
    doc.text(`Tax (${invoice.tax_rate}%): ${formatCurrency(invoice.tax_amount)}`, cx, y, { align: 'center' })
    y += 7
  }
  if (invoice.discount > 0) {
    doc.setFont('helvetica', 'normal')
    doc.text(`Discount: -${formatCurrency(invoice.discount)}`, cx, y, { align: 'center' })
    y += 7
  }
  y += 3
  doc.setFont('helvetica', 'bold')
  doc.setFontSize(18)
  setText(doc, c.primary)
  doc.text(formatCurrency(invoice.total), cx, y, { align: 'center' })

  // --- Notes ---
  y += 12
  drawNotes(doc, invoice, margin, contentW, y, c.bodyText)

  return doc
}


// ===========================================================================
// 5. CLASSIC - Traditional layout, burgundy accents, bordered grid
// ===========================================================================

function renderClassic(
  config: InvoiceTemplateConfig,
  invoice: Invoice,
  client: Client,
  items: InvoiceItem[],
  biz: BusinessInfo,
): jsPDF {
  const doc = new jsPDF({ unit: 'mm', format: 'a4' })
  const margin = 20
  const pageW = 210
  const contentW = pageW - margin * 2
  const c = config.colors

  // --- Two-column header: biz left, INVOICE + meta right ---
  let y = 20
  const logoH = drawLogo(doc, biz.logo, margin, y, 16)
  y += logoH

  doc.setFont('helvetica', 'bold')
  doc.setFontSize(14)
  setText(doc, c.bodyText)
  doc.text(biz.name || '', margin, y)
  y += 5
  doc.setFont('helvetica', 'normal')
  doc.setFontSize(10)
  if (biz.address) { doc.text(biz.address, margin, y); y += 5 }
  if (biz.email) { doc.text(biz.email, margin, y); y += 5 }
  if (biz.phone) { doc.text(biz.phone, margin, y); y += 5 }

  // Right: INVOICE + meta
  let ry = 20
  doc.setFont('helvetica', 'bold')
  doc.setFontSize(28)
  setText(doc, c.primary)
  doc.text('INVOICE', pageW - margin, ry, { align: 'right' })
  ry += 8
  doc.setFont('helvetica', 'normal')
  doc.setFontSize(10)
  setText(doc, c.bodyText)
  doc.text(`# ${invoice.invoice_number}`, pageW - margin, ry, { align: 'right' })
  ry += 6
  doc.text(`Date: ${formatDate(invoice.date)}`, pageW - margin, ry, { align: 'right' })
  ry += 6
  if (invoice.due_date) {
    doc.setFont('helvetica', 'bold')
    doc.setFontSize(12)
    setText(doc, c.primary)
    doc.text(`Due: ${formatDate(invoice.due_date)}`, pageW - margin, ry, { align: 'right' })
  }

  // Thin burgundy rule
  y = Math.max(y, ry) + 4
  setDraw(doc, c.primary)
  doc.setLineWidth(1)
  doc.line(margin, y, pageW - margin, y)
  y += 8

  // --- From / To ---
  const fromEndY = drawFromColumn(doc, biz, margin, y, c.bodyText, c.primary, 70)
  const toEndY = drawToColumn(doc, client, pageW / 2 + 5, y, c.bodyText, c.primary, 70)
  y = Math.max(fromEndY, toEndY) + 10

  // --- Table: bordered grid, burgundy header ---
  const layout = tableLayout(margin, contentW)
  const rowH = 9
  const padX = 4

  // Header bg
  setFill(doc, c.tableHeaderBg)
  doc.rect(margin, y, contentW, rowH, 'F')
  drawHeaderText(doc, layout, y, rowH, c.tableHeaderText, padX)

  // Header border
  setDraw(doc, c.tableBorder)
  doc.setLineWidth(0.3)
  doc.rect(margin, y, contentW, rowH, 'S')
  y += rowH

  // Rows with bordered grid + alternating warm gray
  for (let i = 0; i < items.length; i++) {
    if (pageBreak(doc, y)) y = 20
    // Alternating bg
    if (i % 2 === 1) {
      setFill(doc, c.tableRowAlt)
      doc.rect(margin, y, contentW, rowH, 'F')
    }
    y = drawItemRow(doc, items[i], layout, y, rowH, c.bodyText, padX)
    // Cell borders
    setDraw(doc, c.tableBorder)
    doc.setLineWidth(0.3)
    for (let col = 0; col < 4; col++) {
      doc.rect(layout.colX[col], y - rowH, layout.colW[col], rowH, 'S')
    }
  }

  // --- Totals ---
  y += 10
  y = drawTotals(doc, invoice, margin + contentW, y, c.bodyText, c.totalHighlight, 18)

  // --- Notes ---
  y += 12
  drawNotes(doc, invoice, margin, contentW, y, c.bodyText)

  return doc
}


// ===========================================================================
// 6. MODERN - Teal accents, borderless, teal header text
// ===========================================================================

function renderModern(
  config: InvoiceTemplateConfig,
  invoice: Invoice,
  client: Client,
  items: InvoiceItem[],
  biz: BusinessInfo,
): jsPDF {
  const doc = new jsPDF({ unit: 'mm', format: 'a4' })
  const margin = 20
  const pageW = 210
  const contentW = pageW - margin * 2
  const c = config.colors

  // --- "INVOICE" 28pt top-left ---
  let y = 28
  doc.setFont('helvetica', 'bold')
  doc.setFontSize(28)
  setText(doc, c.headerText)
  doc.text('INVOICE', margin, y)
  y += 8

  // Invoice meta below
  doc.setFont('helvetica', 'normal')
  doc.setFontSize(10)
  setText(doc, c.bodyText)
  doc.text(`# ${invoice.invoice_number}`, margin, y)
  y += 5
  doc.text(`Date: ${formatDate(invoice.date)}`, margin, y)
  y += 5
  if (invoice.due_date) {
    doc.setFont('helvetica', 'bold')
    doc.setFontSize(12)
    setText(doc, c.primary)
    doc.text(`Due: ${formatDate(invoice.due_date)}`, margin, y)
    y += 5
  }

  // Biz info right side
  let bizY = 22
  doc.setFont('helvetica', 'bold')
  doc.setFontSize(14)
  setText(doc, c.bodyText)
  doc.text(biz.name || '', pageW - margin, bizY, { align: 'right' })
  bizY += 6
  doc.setFont('helvetica', 'normal')
  doc.setFontSize(10)
  if (biz.address) { doc.text(biz.address, pageW - margin, bizY, { align: 'right' }); bizY += 5 }
  if (biz.email) { doc.text(biz.email, pageW - margin, bizY, { align: 'right' }); bizY += 5 }
  if (biz.phone) { doc.text(biz.phone, pageW - margin, bizY, { align: 'right' }); bizY += 5 }

  // Thin teal line separator
  y = Math.max(y, bizY) + 4
  setDraw(doc, c.primary)
  doc.setLineWidth(0.5)
  doc.line(margin, y, pageW - margin, y)
  y += 8

  // --- From / To ---
  const fromEndY = drawFromColumn(doc, biz, margin, y, c.bodyText, c.primary, 70)
  const toEndY = drawToColumn(doc, client, pageW / 2 + 5, y, c.bodyText, c.primary, 70)
  y = Math.max(fromEndY, toEndY) + 10

  // --- Table: borderless, teal bottom borders, teal header TEXT (no bg) ---
  const layout = tableLayout(margin, contentW)
  const rowH = 9
  const padX = 4

  // Header (teal text, no bg)
  drawHeaderText(doc, layout, y, rowH, c.tableHeaderText, padX)
  y += rowH
  // Teal line below header
  setDraw(doc, c.primary)
  doc.setLineWidth(0.5)
  doc.line(margin, y, margin + contentW, y)

  // Rows with teal bottom borders
  for (const item of items) {
    if (pageBreak(doc, y)) y = 20
    y = drawItemRow(doc, item, layout, y, rowH, c.bodyText, padX)
    setDraw(doc, c.tableBorder)
    doc.setLineWidth(0.2)
    doc.line(margin, y, margin + contentW, y)
  }

  // --- Totals with subtle teal bg strip ---
  y += 10
  const totalRightX = margin + contentW
  doc.setFont('helvetica', 'normal')
  doc.setFontSize(10)
  setText(doc, c.bodyText)
  doc.text('Subtotal', totalRightX - 50, y)
  doc.text(formatCurrency(invoice.subtotal), totalRightX, y, { align: 'right' })
  y += 7
  if (invoice.tax_rate > 0) {
    doc.text(`Tax (${invoice.tax_rate}%)`, totalRightX - 50, y)
    doc.text(formatCurrency(invoice.tax_amount), totalRightX, y, { align: 'right' })
    y += 7
  }
  if (invoice.discount > 0) {
    doc.text('Discount', totalRightX - 50, y)
    doc.text(`-${formatCurrency(invoice.discount)}`, totalRightX, y, { align: 'right' })
    y += 7
  }
  y += 3
  // Subtle teal bg strip
  setFill(doc, c.tableRowAlt)
  doc.rect(totalRightX - 65, y - 5, 65, 10, 'F')
  doc.setFont('helvetica', 'bold')
  doc.setFontSize(18)
  setText(doc, c.totalHighlight)
  doc.text('TOTAL', totalRightX - 60, y)
  doc.text(formatCurrency(invoice.total), totalRightX, y, { align: 'right' })

  // --- Notes ---
  y += 12
  drawNotes(doc, invoice, margin, contentW, y, c.bodyText)

  return doc
}


// ===========================================================================
// 7. ELEGANT - Gold double-rule accents, centered layout
// ===========================================================================

function renderElegant(
  config: InvoiceTemplateConfig,
  invoice: Invoice,
  client: Client,
  items: InvoiceItem[],
  biz: BusinessInfo,
): jsPDF {
  const doc = new jsPDF({ unit: 'mm', format: 'a4' })
  const margin = 20
  const pageW = 210
  const contentW = pageW - margin * 2
  const cx = pageW / 2
  const c = config.colors
  const gold = c.primary

  // --- Gold double-rule at top ---
  setFill(doc, gold)
  doc.rect(margin, 15, contentW, 0.4, 'F')
  doc.rect(margin, 16.5, contentW, 0.4, 'F')

  // "INVOICE" centered
  let y = 26
  doc.setFont('helvetica', 'bold')
  doc.setFontSize(28)
  setText(doc, c.headerText)
  doc.text('INVOICE', cx, y, { align: 'center' })
  y += 7

  // Biz centered
  doc.setFontSize(14)
  doc.text(biz.name || '', cx, y, { align: 'center' })
  y += 5
  doc.setFont('helvetica', 'normal')
  doc.setFontSize(10)
  setText(doc, c.bodyText)
  if (biz.address) { doc.text(biz.address, cx, y, { align: 'center' }); y += 5 }
  if (biz.email) { doc.text(biz.email, cx, y, { align: 'center' }); y += 5 }
  if (biz.phone) { doc.text(biz.phone, cx, y, { align: 'center' }); y += 5 }

  // Another double-rule
  y += 2
  setFill(doc, gold)
  doc.rect(margin, y, contentW, 0.4, 'F')
  doc.rect(margin, y + 1.5, contentW, 0.4, 'F')
  y += 8

  // Invoice meta left + Bill To right
  doc.setFont('helvetica', 'normal')
  doc.setFontSize(10)
  setText(doc, c.bodyText)
  const metaY = y
  doc.text(`Invoice: ${invoice.invoice_number}`, margin, y); y += 6
  doc.text(`Date: ${formatDate(invoice.date)}`, margin, y); y += 6
  if (invoice.due_date) {
    doc.setFont('helvetica', 'bold')
    doc.setFontSize(12)
    setText(doc, gold)
    doc.text(`Due: ${formatDate(invoice.due_date)}`, margin, y)
    y += 6
  }

  // Bill To right
  let billY = metaY
  doc.setFont('helvetica', 'bold')
  doc.setFontSize(11)
  setText(doc, gold)
  trackedText(doc, 'BILL TO', pageW - margin, billY, { align: 'right' })
  billY += 6
  doc.setFont('helvetica', 'normal')
  doc.setFontSize(10)
  setText(doc, c.bodyText)
  if (client.name) { doc.text(client.name, pageW - margin, billY, { align: 'right' }); billY += 5 }
  if (client.email) { doc.text(client.email, pageW - margin, billY, { align: 'right' }); billY += 5 }
  if (client.address) { doc.text(client.address, pageW - margin, billY, { align: 'right' }); billY += 5 }

  y = Math.max(y, billY) + 8

  // --- Table: gold double-rule above/below header, single gold rules between rows ---
  const layout = tableLayout(margin, contentW)
  const rowH = 9
  const padX = 4

  // Double-rule above header
  setFill(doc, gold)
  doc.rect(margin, y, contentW, 0.4, 'F')
  doc.rect(margin, y + 1.5, contentW, 0.4, 'F')
  y += 3

  drawHeaderText(doc, layout, y, rowH, c.headerText, padX)
  y += rowH

  // Double-rule below header
  setFill(doc, gold)
  doc.rect(margin, y, contentW, 0.4, 'F')
  doc.rect(margin, y + 1.5, contentW, 0.4, 'F')
  y += 3

  // Rows with single gold rules
  for (const item of items) {
    if (pageBreak(doc, y)) y = 20
    y = drawItemRow(doc, item, layout, y, rowH, c.bodyText, padX)
    // Single gold line
    setFill(doc, gold)
    doc.rect(margin, y, contentW, 0.25, 'F')
    y += 1
  }

  // --- Totals ---
  y += 8
  y = drawTotals(doc, invoice, margin + contentW, y, c.bodyText, gold, 18)

  // --- Notes ---
  y += 12
  drawNotes(doc, invoice, margin, contentW, y, c.bodyText)

  return doc
}


// ===========================================================================
// 8. CREATIVE - Purple sidebar, card-style rows
// ===========================================================================

function renderCreative(
  config: InvoiceTemplateConfig,
  invoice: Invoice,
  client: Client,
  items: InvoiceItem[],
  biz: BusinessInfo,
): jsPDF {
  const doc = new jsPDF({ unit: 'mm', format: 'a4' })
  const pageW = 210
  const c = config.colors

  // --- Narrow purple rect full page height ---
  setFill(doc, c.primary)
  doc.rect(0, 0, 6, 297, 'F')

  // Content offset 14mm from left
  const leftM = 14
  const rightM = 20
  const contentW = pageW - leftM - rightM

  // --- "INVOICE" in purple ---
  let y = 28
  doc.setFont('helvetica', 'bold')
  doc.setFontSize(28)
  setText(doc, c.primary)
  doc.text('INVOICE', leftM, y)
  y += 8

  // Invoice meta
  doc.setFont('helvetica', 'normal')
  doc.setFontSize(10)
  setText(doc, c.bodyText)
  doc.text(`# ${invoice.invoice_number}  |  ${formatDate(invoice.date)}${invoice.due_date ? '  |  Due: ' + formatDate(invoice.due_date) : ''}`, leftM, y)
  y += 8

  // Biz info right side
  let bizY = 22
  doc.setFont('helvetica', 'bold')
  doc.setFontSize(14)
  setText(doc, c.headerText)
  doc.text(biz.name || '', pageW - rightM, bizY, { align: 'right' })
  bizY += 6
  doc.setFont('helvetica', 'normal')
  doc.setFontSize(10)
  setText(doc, c.bodyText)
  if (biz.address) { doc.text(biz.address, pageW - rightM, bizY, { align: 'right' }); bizY += 5 }
  if (biz.email) { doc.text(biz.email, pageW - rightM, bizY, { align: 'right' }); bizY += 5 }
  if (biz.phone) { doc.text(biz.phone, pageW - rightM, bizY, { align: 'right' }); bizY += 5 }

  y = Math.max(y, bizY) + 4

  // --- From / To ---
  const fromEndY = drawFromColumn(doc, biz, leftM, y, c.bodyText, c.primary, 65)
  const toEndY = drawToColumn(doc, client, pageW / 2 + 5, y, c.bodyText, c.primary, 65)
  y = Math.max(fromEndY, toEndY) + 10

  // --- Table: card-like rows ---
  const layout = tableLayout(leftM, contentW)
  const rowH = 10
  const padX = 4

  // Header
  doc.setFont('helvetica', 'bold')
  doc.setFontSize(9)
  setText(doc, c.tableHeaderText)
  drawHeaderText(doc, layout, y, rowH, c.tableHeaderText, padX)
  y += rowH

  // Rows as faint purple bg cards
  for (const item of items) {
    if (pageBreak(doc, y)) {
      y = 20
      // Redraw sidebar on new page
      setFill(doc, c.primary)
      doc.rect(0, 0, 6, 297, 'F')
    }
    // Card bg
    setFill(doc, c.tableRowAlt)
    doc.rect(leftM, y + 1, contentW, rowH - 2, 'F')
    y = drawItemRow(doc, item, layout, y, rowH, c.bodyText, padX)
  }

  // --- Totals ---
  y += 10
  y = drawTotals(doc, invoice, leftM + contentW, y, c.bodyText, c.totalHighlight, 18)

  // --- Notes ---
  y += 12
  drawNotes(doc, invoice, leftM, contentW, y, c.bodyText)

  return doc
}


// ===========================================================================
// 9. COMPACT - Data-dense layout with tight spacing
// ===========================================================================

function renderCompact(
  config: InvoiceTemplateConfig,
  invoice: Invoice,
  client: Client,
  items: InvoiceItem[],
  biz: BusinessInfo,
): jsPDF {
  const doc = new jsPDF({ unit: 'mm', format: 'a4' })
  const margin = 15 // tighter margins
  const pageW = 210
  const contentW = pageW - margin * 2
  const c = config.colors

  // --- Single-line header: biz name left, INVOICE #XXX right ---
  let y = 18
  doc.setFont('helvetica', 'bold')
  doc.setFontSize(12)
  setText(doc, c.headerText)
  doc.text(biz.name || '', margin, y)
  doc.text(`INVOICE #${invoice.invoice_number}`, pageW - margin, y, { align: 'right' })
  y += 5

  // Date and due right below
  doc.setFont('helvetica', 'normal')
  doc.setFontSize(9)
  setText(doc, c.bodyText)
  if (biz.email) doc.text(biz.email, margin, y)
  doc.text(`Date: ${formatDate(invoice.date)}${invoice.due_date ? '  |  Due: ' + formatDate(invoice.due_date) : ''}`, pageW - margin, y, { align: 'right' })
  y += 5
  if (biz.phone) doc.text(biz.phone, margin, y)
  y += 7

  // --- Tight From/To ---
  doc.setFont('helvetica', 'bold')
  doc.setFontSize(9)
  setText(doc, c.primary)
  trackedText(doc, 'FROM', margin, y)
  trackedText(doc, 'TO', pageW / 2 + 5, y)
  y += 5

  doc.setFont('helvetica', 'normal')
  doc.setFontSize(9)
  setText(doc, c.bodyText)
  let fromY = y
  if (biz.name) { doc.text(biz.name, margin, fromY); fromY += 4 }
  if (biz.address) { doc.text(biz.address, margin, fromY); fromY += 4 }

  let toY = y
  if (client.name) { doc.text(client.name, pageW / 2 + 5, toY); toY += 4 }
  if (client.email) { doc.text(client.email, pageW / 2 + 5, toY); toY += 4 }
  if (client.address) { doc.text(client.address, pageW / 2 + 5, toY); toY += 4 }

  y = Math.max(fromY, toY) + 6

  // --- Table: tight zebra, 7mm rows, no borders ---
  const layout = tableLayout(margin, contentW)
  const rowH = 7
  const padX = 3

  // Header
  setFill(doc, c.tableHeaderBg)
  doc.rect(margin, y, contentW, rowH, 'F')
  doc.setFont('helvetica', 'bold')
  doc.setFontSize(8)
  setText(doc, c.tableHeaderText)
  const headerTextY = y + rowH * 0.65
  trackedText(doc, 'DESCRIPTION', layout.colX[0] + padX, headerTextY)
  trackedText(doc, 'QTY', layout.colX[1] + padX, headerTextY)
  doc.text('RATE', layout.colX[2] + layout.colW[2] - padX, headerTextY, { align: 'right' })
  doc.text('AMOUNT', layout.colX[3] + layout.colW[3] - padX, headerTextY, { align: 'right' })
  doc.setCharSpace(0)
  y += rowH

  // Rows
  for (let i = 0; i < items.length; i++) {
    if (pageBreak(doc, y)) y = 15
    if (i % 2 === 0) {
      setFill(doc, c.tableRowAlt)
      doc.rect(margin, y, contentW, rowH, 'F')
    }
    doc.setFont('helvetica', 'normal')
    doc.setFontSize(9)
    setText(doc, c.bodyText)
    const textY = y + rowH * 0.62
    const desc = truncateDesc(doc, items[i].description, layout.colW[0] - padX * 2)
    doc.text(desc, layout.colX[0] + padX, textY)
    doc.text(String(items[i].quantity), layout.colX[1] + padX, textY)
    doc.text(formatCurrency(items[i].rate), layout.colX[2] + layout.colW[2] - padX, textY, { align: 'right' })
    doc.text(formatCurrency(items[i].amount), layout.colX[3] + layout.colW[3] - padX, textY, { align: 'right' })
    y += rowH
  }

  // --- Totals (subtle, right-aligned) ---
  y += 6
  const totalRightX = margin + contentW
  doc.setFont('helvetica', 'normal')
  doc.setFontSize(9)
  setText(doc, c.bodyText)
  doc.text(`Subtotal: ${formatCurrency(invoice.subtotal)}`, totalRightX, y, { align: 'right' })
  y += 5
  if (invoice.tax_rate > 0) {
    doc.text(`Tax (${invoice.tax_rate}%): ${formatCurrency(invoice.tax_amount)}`, totalRightX, y, { align: 'right' })
    y += 5
  }
  if (invoice.discount > 0) {
    doc.text(`Discount: -${formatCurrency(invoice.discount)}`, totalRightX, y, { align: 'right' })
    y += 5
  }
  y += 2
  doc.setFont('helvetica', 'bold')
  doc.setFontSize(14)
  setText(doc, c.totalHighlight)
  doc.text(`Total: ${formatCurrency(invoice.total)}`, totalRightX, y, { align: 'right' })

  // --- Notes ---
  y += 10
  drawNotes(doc, invoice, margin, contentW, y, c.bodyText)

  return doc
}


// ===========================================================================
// 10. DARK - Full dark background with cyan highlights
// ===========================================================================

function renderDark(
  config: InvoiceTemplateConfig,
  invoice: Invoice,
  client: Client,
  items: InvoiceItem[],
  biz: BusinessInfo,
): jsPDF {
  const doc = new jsPDF({ unit: 'mm', format: 'a4' })
  const margin = 20
  const pageW = 210
  const contentW = pageW - margin * 2
  const c = config.colors

  // --- Full-page dark bg ---
  setFill(doc, c.background)
  doc.rect(0, 0, 210, 297, 'F')

  // "INVOICE" 28pt cyan
  let y = 28
  doc.setFont('helvetica', 'bold')
  doc.setFontSize(28)
  setText(doc, c.primary)
  doc.text('INVOICE', margin, y)
  y += 8

  // Invoice meta in light text
  doc.setFont('helvetica', 'normal')
  doc.setFontSize(10)
  setText(doc, c.bodyText)
  doc.text(`# ${invoice.invoice_number}`, margin, y)
  y += 5
  doc.text(`Date: ${formatDate(invoice.date)}`, margin, y)
  y += 5
  if (invoice.due_date) {
    doc.setFont('helvetica', 'bold')
    doc.setFontSize(12)
    setText(doc, c.primary)
    doc.text(`Due: ${formatDate(invoice.due_date)}`, margin, y)
    y += 5
  }

  // Biz info right in light text
  let bizY = 22
  doc.setFont('helvetica', 'bold')
  doc.setFontSize(14)
  setText(doc, c.headerText)
  doc.text(biz.name || '', pageW - margin, bizY, { align: 'right' })
  bizY += 6
  doc.setFont('helvetica', 'normal')
  doc.setFontSize(10)
  setText(doc, c.bodyText)
  if (biz.address) { doc.text(biz.address, pageW - margin, bizY, { align: 'right' }); bizY += 5 }
  if (biz.email) { doc.text(biz.email, pageW - margin, bizY, { align: 'right' }); bizY += 5 }
  if (biz.phone) { doc.text(biz.phone, pageW - margin, bizY, { align: 'right' }); bizY += 5 }

  y = Math.max(y, bizY) + 6

  // --- From / To in light text ---
  doc.setFont('helvetica', 'bold')
  doc.setFontSize(11)
  setText(doc, c.primary)
  trackedText(doc, 'FROM', margin, y)
  trackedText(doc, 'TO', pageW / 2 + 5, y)
  y += 6

  doc.setFont('helvetica', 'normal')
  doc.setFontSize(10)
  setText(doc, c.bodyText)
  let fromY = y
  if (biz.name) { doc.text(biz.name, margin, fromY); fromY += 5 }
  if (biz.address) { doc.text(biz.address, margin, fromY); fromY += 5 }
  if (biz.email) { doc.text(biz.email, margin, fromY); fromY += 5 }

  let toY = y
  setText(doc, c.headerText)
  if (client.name) { doc.text(client.name, pageW / 2 + 5, toY); toY += 5 }
  setText(doc, c.bodyText)
  if (client.email) { doc.text(client.email, pageW / 2 + 5, toY); toY += 5 }
  if (client.address) { doc.text(client.address, pageW / 2 + 5, toY); toY += 5 }

  y = Math.max(fromY, toY) + 10

  // --- Table: very dark header, cyan names, alternating dark rows ---
  const layout = tableLayout(margin, contentW)
  const rowH = 9
  const padX = 4

  // Very dark header
  setFill(doc, c.tableHeaderBg)
  doc.rect(margin, y, contentW, rowH, 'F')
  drawHeaderText(doc, layout, y, rowH, c.tableHeaderText, padX)
  y += rowH

  // Rows with alternating dark
  for (let i = 0; i < items.length; i++) {
    if (pageBreak(doc, y)) {
      y = 20
      setFill(doc, c.background)
      doc.rect(0, 0, 210, 297, 'F')
    }
    if (i % 2 === 1) {
      setFill(doc, c.tableRowAlt)
      doc.rect(margin, y, contentW, rowH, 'F')
    }
    y = drawItemRow(doc, items[i], layout, y, rowH, c.bodyText, padX)
  }

  // --- Totals: cyan 18pt ---
  y += 10
  y = drawTotals(doc, invoice, margin + contentW, y, c.bodyText, c.totalHighlight, 18)

  // --- Notes ---
  y += 12
  drawNotes(doc, invoice, margin, contentW, y, c.bodyText)

  return doc
}


// ===========================================================================
// 11. VIBRANT - Coral header band, warm tones
// ===========================================================================

function renderVibrant(
  config: InvoiceTemplateConfig,
  invoice: Invoice,
  client: Client,
  items: InvoiceItem[],
  biz: BusinessInfo,
): jsPDF {
  const doc = new jsPDF({ unit: 'mm', format: 'a4' })
  const margin = 20
  const pageW = 210
  const contentW = pageW - margin * 2
  const c = config.colors

  // --- Full-width coral rect ---
  setFill(doc, c.headerBg)
  doc.rect(0, 0, 210, 45, 'F')

  // White "INVOICE" + biz inside
  doc.setFont('helvetica', 'bold')
  doc.setFontSize(28)
  setText(doc, c.headerText)
  doc.text('INVOICE', margin, 22)

  // Biz name right in white
  doc.setFontSize(14)
  doc.text(biz.name || '', pageW - margin, 18, { align: 'right' })
  doc.setFont('helvetica', 'normal')
  doc.setFontSize(9)
  let bizY = 25
  if (biz.address) { doc.text(biz.address, pageW - margin, bizY, { align: 'right' }); bizY += 5 }
  if (biz.email) { doc.text(biz.email, pageW - margin, bizY, { align: 'right' }); bizY += 5 }
  if (biz.phone) { doc.text(biz.phone, pageW - margin, bizY, { align: 'right' }); bizY += 5 }

  // Invoice meta white inside band
  doc.setFontSize(10)
  doc.text(`# ${invoice.invoice_number}`, margin, 32)
  if (invoice.due_date) {
    doc.text(`Due: ${formatDate(invoice.due_date)}`, margin, 38)
  }

  // --- From / To below band ---
  let y = 55
  const fromEndY = drawFromColumn(doc, biz, margin, y, c.bodyText, c.primary, 70)
  const toEndY = drawToColumn(doc, client, pageW / 2 + 5, y, c.bodyText, c.primary, 70)
  y = Math.max(fromEndY, toEndY) + 10

  // --- Light warm table ---
  const layout = tableLayout(margin, contentW)
  const rowH = 9
  const padX = 4

  // Header
  setFill(doc, c.tableHeaderBg)
  doc.rect(margin, y, contentW, rowH, 'F')
  drawHeaderText(doc, layout, y, rowH, c.tableHeaderText, padX)
  y += rowH

  // Rows
  for (let i = 0; i < items.length; i++) {
    if (pageBreak(doc, y)) y = 20
    if (i % 2 === 1) {
      setFill(doc, c.tableRowAlt)
      doc.rect(margin, y, contentW, rowH, 'F')
    }
    y = drawItemRow(doc, items[i], layout, y, rowH, c.bodyText, padX)
  }

  // --- Totals: coral 18pt ---
  y += 10
  y = drawTotals(doc, invoice, margin + contentW, y, c.bodyText, c.totalHighlight, 18)

  // --- Notes ---
  y += 12
  drawNotes(doc, invoice, margin, contentW, y, c.bodyText)

  return doc
}


// ===========================================================================
// 12. CORPORATE - Blue header with info bar below
// ===========================================================================

function renderCorporate(
  config: InvoiceTemplateConfig,
  invoice: Invoice,
  client: Client,
  items: InvoiceItem[],
  biz: BusinessInfo,
): jsPDF {
  const doc = new jsPDF({ unit: 'mm', format: 'a4' })
  const margin = 20
  const pageW = 210
  const contentW = pageW - margin * 2
  const c = config.colors

  // --- Blue header rect ---
  setFill(doc, c.headerBg)
  doc.rect(0, 0, 210, 45, 'F')

  // White text inside
  doc.setFont('helvetica', 'bold')
  doc.setFontSize(28)
  setText(doc, c.headerText)
  doc.text('INVOICE', margin, 22)

  doc.setFontSize(14)
  doc.text(biz.name || '', pageW - margin, 18, { align: 'right' })
  doc.setFont('helvetica', 'normal')
  doc.setFontSize(9)
  let bizY = 26
  if (biz.address) { doc.text(biz.address, pageW - margin, bizY, { align: 'right' }); bizY += 5 }
  if (biz.email) { doc.text(biz.email, pageW - margin, bizY, { align: 'right' }); bizY += 5 }
  if (biz.phone) { doc.text(biz.phone, pageW - margin, bizY, { align: 'right' }); bizY += 5 }

  // --- Lighter blue info bar below header ---
  setFill(doc, c.secondary)
  doc.rect(0, 45, 210, 8, 'F')
  doc.setFont('helvetica', 'normal')
  doc.setFontSize(9)
  setText(doc, '#ffffff')
  doc.text(`# ${invoice.invoice_number}`, margin, 50)
  doc.text(`Date: ${formatDate(invoice.date)}`, margin + 45, 50)
  if (invoice.due_date) {
    doc.text(`Due: ${formatDate(invoice.due_date)}`, margin + 95, 50)
  }
  doc.text(`Status: ${invoice.status}`, pageW - margin, 50, { align: 'right' })

  // --- From / To ---
  let y = 63
  const fromEndY = drawFromColumn(doc, biz, margin, y, c.bodyText, c.primary, 70)
  const toEndY = drawToColumn(doc, client, pageW / 2 + 5, y, c.bodyText, c.primary, 70)
  y = Math.max(fromEndY, toEndY) + 10

  // --- Table: bordered, blue header ---
  const layout = tableLayout(margin, contentW)
  const rowH = 9
  const padX = 4

  // Header
  setFill(doc, c.tableHeaderBg)
  doc.rect(margin, y, contentW, rowH, 'F')
  drawHeaderText(doc, layout, y, rowH, c.tableHeaderText, padX)
  y += rowH

  // Rows with thin gray borders
  for (let i = 0; i < items.length; i++) {
    if (pageBreak(doc, y)) y = 20
    if (i % 2 === 1) {
      setFill(doc, c.tableRowAlt)
      doc.rect(margin, y, contentW, rowH, 'F')
    }
    // Thin borders
    setDraw(doc, c.tableBorder)
    doc.setLineWidth(0.2)
    doc.rect(margin, y, contentW, rowH, 'S')
    y = drawItemRow(doc, items[i], layout, y, rowH, c.bodyText, padX)
  }

  // --- Totals: blue 18pt ---
  y += 10
  y = drawTotals(doc, invoice, margin + contentW, y, c.bodyText, c.totalHighlight, 18)

  // --- Notes ---
  y += 12
  drawNotes(doc, invoice, margin, contentW, y, c.bodyText)

  return doc
}


// ===========================================================================
// 13. FRESH - Oversized watermark invoice number
// ===========================================================================

function renderFresh(
  config: InvoiceTemplateConfig,
  invoice: Invoice,
  client: Client,
  items: InvoiceItem[],
  biz: BusinessInfo,
): jsPDF {
  const doc = new jsPDF({ unit: 'mm', format: 'a4' })
  const margin = 20
  const pageW = 210
  const contentW = pageW - margin * 2
  const c = config.colors

  // --- Logo left ---
  let y = 20
  const logoH = drawLogo(doc, biz.logo, margin, y, 16)
  if (logoH > 0) y += logoH

  doc.setFont('helvetica', 'bold')
  doc.setFontSize(14)
  setText(doc, c.headerText)
  doc.text(biz.name || '', margin, y)
  y += 5
  doc.setFont('helvetica', 'normal')
  doc.setFontSize(10)
  setText(doc, c.bodyText)
  if (biz.address) { doc.text(biz.address, margin, y); y += 5 }
  if (biz.email) { doc.text(biz.email, margin, y); y += 5 }
  if (biz.phone) { doc.text(biz.phone, margin, y); y += 5 }

  // --- Large invoice number right side with light blue bg ---
  // Light bg rect behind oversized number
  setFill(doc, c.tableRowAlt)
  doc.rect(pageW - margin - 70, 16, 70, 28, 'F')
  // "INVOICE" 14pt above number
  doc.setFont('helvetica', 'bold')
  doc.setFontSize(14)
  setText(doc, c.primary)
  doc.text('INVOICE', pageW - margin, 24, { align: 'right' })
  // Oversized number ~32pt
  doc.setFontSize(32)
  setText(doc, c.secondary)
  doc.text(invoice.invoice_number, pageW - margin, 38, { align: 'right' })

  // Date/due
  doc.setFont('helvetica', 'normal')
  doc.setFontSize(10)
  setText(doc, c.bodyText)
  doc.text(`Date: ${formatDate(invoice.date)}`, pageW - margin, 48, { align: 'right' })
  if (invoice.due_date) {
    doc.setFont('helvetica', 'bold')
    doc.setFontSize(12)
    setText(doc, c.primary)
    doc.text(`Due: ${formatDate(invoice.due_date)}`, pageW - margin, 55, { align: 'right' })
  }

  // --- From / To ---
  y = Math.max(y, 60) + 4
  const fromEndY = drawFromColumn(doc, biz, margin, y, c.bodyText, c.primary, 70)
  const toEndY = drawToColumn(doc, client, pageW / 2 + 5, y, c.bodyText, c.primary, 70)
  y = Math.max(fromEndY, toEndY) + 10

  // --- Table: sky blue header, light blue zebra ---
  const layout = tableLayout(margin, contentW)
  const rowH = 9
  const padX = 4

  // Header
  setFill(doc, c.tableHeaderBg)
  doc.rect(margin, y, contentW, rowH, 'F')
  drawHeaderText(doc, layout, y, rowH, c.tableHeaderText, padX)
  y += rowH

  // Rows
  for (let i = 0; i < items.length; i++) {
    if (pageBreak(doc, y)) y = 20
    if (i % 2 === 1) {
      setFill(doc, c.tableRowAlt)
      doc.rect(margin, y, contentW, rowH, 'F')
    }
    y = drawItemRow(doc, items[i], layout, y, rowH, c.bodyText, padX)
  }

  // --- Totals: sky blue 18pt ---
  y += 10
  y = drawTotals(doc, invoice, margin + contentW, y, c.bodyText, c.totalHighlight, 18)

  // --- Notes ---
  y += 12
  drawNotes(doc, invoice, margin, contentW, y, c.bodyText)

  return doc
}


// ===========================================================================
// 14. NATURAL - Warm beige full-page background, terracotta accents
// ===========================================================================

function renderNatural(
  config: InvoiceTemplateConfig,
  invoice: Invoice,
  client: Client,
  items: InvoiceItem[],
  biz: BusinessInfo,
): jsPDF {
  const doc = new jsPDF({ unit: 'mm', format: 'a4' })
  const margin = 20
  const pageW = 210
  const contentW = pageW - margin * 2
  const c = config.colors

  // --- Full-page warm beige bg ---
  setFill(doc, c.background)
  doc.rect(0, 0, 210, 297, 'F')

  // "INVOICE" 28pt terracotta
  let y = 28
  doc.setFont('helvetica', 'bold')
  doc.setFontSize(28)
  setText(doc, c.primary)
  doc.text('INVOICE', margin, y)
  y += 8

  // Invoice meta
  doc.setFont('helvetica', 'normal')
  doc.setFontSize(10)
  setText(doc, c.bodyText)
  doc.text(`# ${invoice.invoice_number}`, margin, y)
  y += 5
  doc.text(`Date: ${formatDate(invoice.date)}`, margin, y)
  y += 5
  if (invoice.due_date) {
    doc.setFont('helvetica', 'bold')
    doc.setFontSize(12)
    setText(doc, c.primary)
    doc.text(`Due: ${formatDate(invoice.due_date)}`, margin, y)
    y += 5
  }

  // Biz info right in warm brown
  let bizY = 22
  doc.setFont('helvetica', 'bold')
  doc.setFontSize(14)
  setText(doc, c.headerText)
  doc.text(biz.name || '', pageW - margin, bizY, { align: 'right' })
  bizY += 6
  doc.setFont('helvetica', 'normal')
  doc.setFontSize(10)
  setText(doc, c.bodyText)
  if (biz.address) { doc.text(biz.address, pageW - margin, bizY, { align: 'right' }); bizY += 5 }
  if (biz.email) { doc.text(biz.email, pageW - margin, bizY, { align: 'right' }); bizY += 5 }
  if (biz.phone) { doc.text(biz.phone, pageW - margin, bizY, { align: 'right' }); bizY += 5 }

  y = Math.max(y, bizY) + 6

  // --- From / To ---
  const fromEndY = drawFromColumn(doc, biz, margin, y, c.bodyText, c.primary, 70)
  const toEndY = drawToColumn(doc, client, pageW / 2 + 5, y, c.bodyText, c.primary, 70)
  y = Math.max(fromEndY, toEndY) + 10

  // --- Table: terracotta header, warm cream alternating on beige ---
  const layout = tableLayout(margin, contentW)
  const rowH = 9
  const padX = 4

  // Terracotta header
  setFill(doc, c.tableHeaderBg)
  doc.rect(margin, y, contentW, rowH, 'F')
  drawHeaderText(doc, layout, y, rowH, c.tableHeaderText, padX)
  y += rowH

  // Rows
  for (let i = 0; i < items.length; i++) {
    if (pageBreak(doc, y)) {
      y = 20
      setFill(doc, c.background)
      doc.rect(0, 0, 210, 297, 'F')
    }
    if (i % 2 === 1) {
      setFill(doc, c.tableRowAlt)
      doc.rect(margin, y, contentW, rowH, 'F')
    }
    y = drawItemRow(doc, items[i], layout, y, rowH, c.bodyText, padX)
  }

  // --- Totals: terracotta 18pt ---
  y += 10
  y = drawTotals(doc, invoice, margin + contentW, y, c.bodyText, c.totalHighlight, 18)

  // --- Notes ---
  y += 12
  drawNotes(doc, invoice, margin, contentW, y, c.bodyText)

  return doc
}


// ===========================================================================
// 15. STATEMENT - Total-forward design, hero amount top-right
// ===========================================================================

function renderStatement(
  config: InvoiceTemplateConfig,
  invoice: Invoice,
  client: Client,
  items: InvoiceItem[],
  biz: BusinessInfo,
): jsPDF {
  const doc = new jsPDF({ unit: 'mm', format: 'a4' })
  const margin = 20
  const pageW = 210
  const contentW = pageW - margin * 2
  const c = config.colors
  const rose = c.secondary

  // --- "INVOICE" 16pt normal top-left ---
  let y = 22
  doc.setFont('helvetica', 'normal')
  doc.setFontSize(16)
  setText(doc, c.primary)
  doc.text('INVOICE', margin, y)
  y += 6
  doc.setFontSize(10)
  setText(doc, c.bodyText)
  doc.text(`# ${invoice.invoice_number}`, margin, y)
  y += 5
  doc.text(`Date: ${formatDate(invoice.date)}`, margin, y)
  y += 5
  if (invoice.due_date) {
    doc.text(`Due: ${formatDate(invoice.due_date)}`, margin, y)
    y += 5
  }

  // Biz info below invoice meta
  y += 2
  doc.setFont('helvetica', 'bold')
  doc.setFontSize(11)
  setText(doc, c.bodyText)
  doc.text(biz.name || '', margin, y)
  y += 5
  doc.setFont('helvetica', 'normal')
  doc.setFontSize(10)
  if (biz.address) { doc.text(biz.address, margin, y); y += 5 }
  if (biz.email) { doc.text(biz.email, margin, y); y += 5 }
  if (biz.phone) { doc.text(biz.phone, margin, y); y += 5 }

  // --- TOTAL AMOUNT massive top-right ---
  doc.setFont('helvetica', 'bold')
  doc.setFontSize(11)
  setText(doc, c.bodyText)
  doc.text('TOTAL DUE', pageW - margin, 20, { align: 'right' })

  doc.setFontSize(28)
  setText(doc, rose)
  doc.text(formatCurrency(invoice.total), pageW - margin, 32, { align: 'right' })

  // Due date below total if present
  if (invoice.due_date) {
    doc.setFont('helvetica', 'bold')
    doc.setFontSize(12)
    setText(doc, rose)
    doc.text(`Due: ${formatDate(invoice.due_date)}`, pageW - margin, 40, { align: 'right' })
  }

  // --- From / To below ---
  y = Math.max(y, 50) + 4
  const fromEndY = drawFromColumn(doc, biz, margin, y, c.bodyText, c.primary, 70)
  const toEndY = drawToColumn(doc, client, pageW / 2 + 5, y, c.bodyText, c.primary, 70)
  y = Math.max(fromEndY, toEndY) + 10

  // --- Table: whitespace-only, no borders, no stripes ---
  const layout = tableLayout(margin, contentW)
  const rowH = 9
  const padX = 4

  // Header text only (no bg)
  drawHeaderText(doc, layout, y, rowH, c.tableHeaderText, padX)
  y += rowH

  // Thin separator below header
  setDraw(doc, c.tableBorder)
  doc.setLineWidth(0.3)
  doc.line(margin, y, margin + contentW, y)

  // Rows
  for (const item of items) {
    if (pageBreak(doc, y)) y = 20
    y = drawItemRow(doc, item, layout, y, rowH, c.bodyText, padX)
  }

  // --- Bottom totals: simple summary ---
  y += 8
  setDraw(doc, c.tableBorder)
  doc.setLineWidth(0.3)
  doc.line(margin + contentW - 60, y, margin + contentW, y)
  y += 6
  const totalRightX = margin + contentW
  doc.setFont('helvetica', 'normal')
  doc.setFontSize(10)
  setText(doc, c.bodyText)
  doc.text('Subtotal', totalRightX - 50, y)
  doc.text(formatCurrency(invoice.subtotal), totalRightX, y, { align: 'right' })
  y += 6
  if (invoice.tax_rate > 0) {
    doc.text(`Tax (${invoice.tax_rate}%)`, totalRightX - 50, y)
    doc.text(formatCurrency(invoice.tax_amount), totalRightX, y, { align: 'right' })
    y += 6
  }
  if (invoice.discount > 0) {
    doc.text('Discount', totalRightX - 50, y)
    doc.text(`-${formatCurrency(invoice.discount)}`, totalRightX, y, { align: 'right' })
    y += 6
  }
  y += 2
  doc.setFont('helvetica', 'bold')
  doc.setFontSize(18)
  setText(doc, rose)
  doc.text('TOTAL', totalRightX - 50, y)
  doc.text(formatCurrency(invoice.total), totalRightX, y, { align: 'right' })

  // --- Notes ---
  y += 12
  drawNotes(doc, invoice, margin, contentW, y, c.bodyText)

  return doc
}


// ===========================================================================
// Main export
// ===========================================================================

export function renderInvoicePdf(
  config: InvoiceTemplateConfig,
  invoice: Invoice,
  client: Client,
  items: InvoiceItem[],
  businessInfo: BusinessInfo,
): jsPDF {
  switch (config.layout) {
    case 'clean': return renderClean(config, invoice, client, items, businessInfo)
    case 'professional': return renderProfessional(config, invoice, client, items, businessInfo)
    case 'bold': return renderBold(config, invoice, client, items, businessInfo)
    case 'minimal': return renderMinimal(config, invoice, client, items, businessInfo)
    case 'classic': return renderClassic(config, invoice, client, items, businessInfo)
    case 'modern': return renderModern(config, invoice, client, items, businessInfo)
    case 'elegant': return renderElegant(config, invoice, client, items, businessInfo)
    case 'creative': return renderCreative(config, invoice, client, items, businessInfo)
    case 'compact': return renderCompact(config, invoice, client, items, businessInfo)
    case 'dark': return renderDark(config, invoice, client, items, businessInfo)
    case 'vibrant': return renderVibrant(config, invoice, client, items, businessInfo)
    case 'corporate': return renderCorporate(config, invoice, client, items, businessInfo)
    case 'fresh': return renderFresh(config, invoice, client, items, businessInfo)
    case 'natural': return renderNatural(config, invoice, client, items, businessInfo)
    case 'statement': return renderStatement(config, invoice, client, items, businessInfo)
    default: return renderClean(config, invoice, client, items, businessInfo)
  }
}
