import type { AgendaExportModel } from './export-model'
import type { ExportLogos } from './export-excel'
import { hexToRgb, isLight } from './colors'

/**
 * PDF export for an agenda (jspdf via dynamic import). A4 portrait, manual
 * table layout with row-level pagination so long agendas wrap cleanly and no
 * text is clipped. Logo-tolerant: with no logos the logo band is simply omitted.
 *
 * Logos arrive as PNG data URLs (jspdf decodes PNG natively, so this runs in
 * Node tests too). SVG→PNG rasterisation lives in the browser-only
 * `lib/agenda/logo.ts`.
 */

// A4 portrait in mm
const PAGE_W = 210
const PAGE_H = 297
const MARGIN = 12
const PETROL: [number, number, number] = [3, 116, 147]
const BORDER: [number, number, number] = [193, 197, 203]

// Column widths (mm) — sum = usable width (210 - 2*12 = 186)
const COLS = [
  { key: 'time', width: 20 },
  { key: 'subject', width: 46 },
  { key: 'duration', width: 12 },
  { key: 'responsible', width: 28 },
  { key: 'participants', width: 36 },
  { key: 'info', width: 44 },
] as const

type Doc = import('jspdf').jsPDF

function colX(index: number): number {
  let x = MARGIN
  for (let i = 0; i < index; i += 1) x += COLS[i].width
  return x
}

export async function buildAgendaPdf(
  model: AgendaExportModel,
  logos: ExportLogos = {},
): Promise<Blob> {
  const { jsPDF } = await import('jspdf')
  const doc: Doc = new jsPDF({ orientation: 'portrait', unit: 'mm', format: 'a4' })

  let y = MARGIN

  const ensureSpace = (needed: number) => {
    if (y + needed > PAGE_H - MARGIN) {
      doc.addPage()
      y = MARGIN
    }
  }

  // Logo band — preserve each logo's aspect ratio (fit into a box, no stretching)
  const LOGO_MAX_W = 48
  const LOGO_MAX_H = 16
  const placeLogo = (png: string, anchorX: number, align: 'left' | 'right'): number => {
    try {
      const props = doc.getImageProperties(png)
      if (!props.width || !props.height) return 0
      const ratio = Math.min(LOGO_MAX_W / props.width, LOGO_MAX_H / props.height)
      const w = props.width * ratio
      const h = props.height * ratio
      doc.addImage(png, 'PNG', align === 'right' ? anchorX - w : anchorX, y, w, h)
      return h
    } catch {
      return 0
    }
  }
  let logoHeight = 0
  if (logos.hostLogoPng) {
    logoHeight = Math.max(logoHeight, placeLogo(logos.hostLogoPng, MARGIN, 'left'))
  }
  let rightX = PAGE_W - MARGIN
  for (const png of (logos.supplierLogoPngs ?? []).slice(0, 2)) {
    logoHeight = Math.max(logoHeight, placeLogo(png, rightX, 'right'))
    rightX -= LOGO_MAX_W + 4
  }
  if (logoHeight > 0) y += logoHeight + 4

  // Title
  doc.setFont('helvetica', 'bold')
  doc.setFontSize(16)
  doc.setTextColor(PETROL[0], PETROL[1], PETROL[2])
  doc.text(model.title, MARGIN, y + 5)
  y += 9

  // Meta block
  doc.setTextColor(40, 40, 40)
  doc.setFontSize(9)
  const meta: Array<[string, string]> = [
    [model.labels.supplier, model.supplierName],
    [model.labels.location, model.location],
    [model.labels.date, model.dateRangeLabel],
    [model.labels.objective, model.objective],
  ]
  for (const [key, value] of meta) {
    if (!value) continue
    doc.setFont('helvetica', 'bold')
    doc.text(`${key}:`, MARGIN, y)
    doc.setFont('helvetica', 'normal')
    const lines = doc.splitTextToSize(value, PAGE_W - MARGIN * 2 - 40)
    doc.text(lines, MARGIN + 38, y)
    y += Math.max(5, lines.length * 4.5)
  }

  // Participants as a compact table (Name · Unternehmen · Abteilung · Rolle · E-Mail; Position removed)
  const PART_COLS = [42, 34, 28, 30, 52] as const // sum = 186
  const partColX = (index: number) => {
    let x = MARGIN
    for (let k = 0; k < index; k += 1) x += PART_COLS[k]
    return x
  }
  const PART_HEADERS = ['Name', 'Unternehmen', 'Abteilung', 'Rolle', 'E-Mail']
  const renderParticipantGroup = (heading: string, people: AgendaExportModel['hostParticipants']) => {
    if (people.length === 0) return
    ensureSpace(12)
    doc.setFont('helvetica', 'bold')
    doc.setFontSize(8)
    doc.setTextColor(PETROL[0], PETROL[1], PETROL[2])
    doc.text(heading, MARGIN, y + 3)
    y += 4.5
    doc.setFont('helvetica', 'bold')
    doc.setFontSize(6.5)
    doc.setTextColor(120, 120, 120)
    PART_HEADERS.forEach((h, i) => doc.text(h, partColX(i) + 0.5, y + 2.5))
    y += 3.4
    doc.setFont('helvetica', 'normal')
    doc.setFontSize(7)
    doc.setTextColor(40, 40, 40)
    for (const person of people) {
      ensureSpace(4)
      const vals = [person.name, person.company, person.department, person.role, person.email]
      vals.forEach((v, i) => {
        const line = doc.splitTextToSize(String(v ?? ''), PART_COLS[i] - 1.5)[0] ?? ''
        doc.text(line, partColX(i) + 0.5, y + 2.8)
      })
      doc.setDrawColor(BORDER[0], BORDER[1], BORDER[2])
      doc.line(MARGIN, y + 3.6, PAGE_W - MARGIN, y + 3.6)
      y += 4
    }
    y += 1.5
  }
  y += 2
  renderParticipantGroup(model.labels.hostParticipants, model.hostParticipants)
  renderParticipantGroup(model.labels.supplierParticipants, model.supplierParticipants)
  y += 2

  const drawColumnHeader = () => {
    const headers = [model.columns.time, model.columns.subject, model.columns.duration, model.columns.responsible, model.columns.participants, model.columns.info]
    doc.setFont('helvetica', 'bold')
    doc.setFontSize(7.5)
    // Wrap each header within its column width so nothing runs off the page.
    const wrapped = headers.map((header, index) => doc.splitTextToSize(header, COLS[index].width - 3))
    const lineCount = Math.max(1, ...wrapped.map((w) => w.length))
    const headerHeight = lineCount * 3.2 + 2.5
    doc.setFillColor(224, 242, 255)
    doc.rect(MARGIN, y, PAGE_W - MARGIN * 2, headerHeight, 'F')
    doc.setTextColor(40, 40, 40)
    wrapped.forEach((lines, index) => {
      doc.text(lines, colX(index) + 1.5, y + 3.2)
    })
    y += headerHeight
  }

  doc.setFontSize(8)
  for (const day of model.days) {
    ensureSpace(14)
    // Day band
    const dayText = [day.heading, day.dateLabel].filter(Boolean).join(' — ') + (day.isTravelDay ? '  (Travel)' : '')
    doc.setFillColor(PETROL[0], PETROL[1], PETROL[2])
    doc.rect(MARGIN, y, PAGE_W - MARGIN * 2, 7, 'F')
    doc.setFont('helvetica', 'bold')
    doc.setFontSize(10)
    doc.setTextColor(255, 255, 255)
    doc.text(dayText, MARGIN + 1.5, y + 4.8)
    y += 7

    drawColumnHeader()
    doc.setFont('helvetica', 'normal')
    doc.setFontSize(7.5)
    doc.setTextColor(40, 40, 40)

    for (const row of day.rows) {
      const cellLines = COLS.map((col) =>
        doc.splitTextToSize(String((row as unknown as Record<string, string>)[col.key] ?? ''), col.width - 3),
      )
      const lineCount = Math.max(1, ...cellLines.map((l) => l.length))
      const rowHeight = lineCount * 3.5 + 1.5

      if (y + rowHeight > PAGE_H - MARGIN) {
        doc.addPage()
        y = MARGIN
        drawColumnHeader()
        doc.setFont('helvetica', 'normal')
        doc.setFontSize(8)
        doc.setTextColor(40, 40, 40)
      }

      const tintedRow = row.color.toUpperCase() !== '#FFFFFF'
      if (tintedRow) {
        const [cr, cg, cb] = hexToRgb(row.color)
        doc.setFillColor(cr, cg, cb)
        doc.rect(MARGIN, y, PAGE_W - MARGIN * 2, rowHeight, 'F')
      }
      // Contrast: light text on dark fills, dark text otherwise.
      const onDark = tintedRow && !isLight(row.color)
      doc.setTextColor(onDark ? 255 : 40, onDark ? 255 : 40, onDark ? 255 : 40)
      cellLines.forEach((lines, index) => {
        doc.text(lines, colX(index) + 1.5, y + 3.2)
      })
      doc.setTextColor(40, 40, 40)
      doc.setDrawColor(BORDER[0], BORDER[1], BORDER[2])
      doc.line(MARGIN, y + rowHeight, PAGE_W - MARGIN, y + rowHeight)
      y += rowHeight
    }
    y += 4
  }

  // Page footer with numbers
  const pageCount = doc.getNumberOfPages()
  for (let page = 1; page <= pageCount; page += 1) {
    doc.setPage(page)
    doc.setFontSize(7)
    doc.setTextColor(120, 120, 120)
    doc.text(`${page} / ${pageCount}`, PAGE_W - MARGIN, PAGE_H - 5, { align: 'right' })
  }

  const arrayBuffer = doc.output('arraybuffer')
  return new Blob([arrayBuffer], { type: 'application/pdf' })
}
