import type { AgendaExportModel } from './export-model'
import { hexToArgb, isLight } from './colors'

/**
 * Excel export for an agenda. Runs client-side (ExcelJS via dynamic import,
 * same pattern as `lib/export/export-service.ts`) but is pure enough to also
 * run under Node for tests.
 *
 * Logos are passed in as PNG data URLs (the SVG→PNG rasterisation happens in
 * the browser-only `lib/agenda/logo.ts`). Everything is logo-tolerant: with no
 * logos the workbook still renders.
 */

export interface ExportLogos {
  /** Host-organisation logo as a PNG data URL. */
  hostLogoPng?: string | null
  /** Up to two supplier logos as PNG data URLs. */
  supplierLogoPngs?: string[]
}

const PETROL = 'FF037493' // DCT petrol primary
const PETROL_SOFT = 'FFE0F2FF'
const WHITE = 'FFFFFFFF'
const COLUMN_COUNT = 6

function dataUrlToBase64(dataUrl: string): string {
  const comma = dataUrl.indexOf(',')
  return comma >= 0 ? dataUrl.slice(comma + 1) : dataUrl
}

/** Read a PNG's intrinsic width/height from its base64 IHDR (browser + Node). */
function pngSize(base64: string): { width: number; height: number } | null {
  try {
    const head = base64.slice(0, 64)
    const binary =
      typeof atob === 'function' ? atob(head) : Buffer.from(head, 'base64').toString('binary')
    if (binary.length < 24) return null
    const at = (i: number) => binary.charCodeAt(i)
    const width = (at(16) << 24) | (at(17) << 16) | (at(18) << 8) | at(19)
    const height = (at(20) << 24) | (at(21) << 16) | (at(22) << 8) | at(23)
    return width > 0 && height > 0 ? { width, height } : null
  } catch {
    return null
  }
}

/** Build an agenda workbook as a Blob. Header band + day tables, landscape. */
export async function buildAgendaWorkbook(
  model: AgendaExportModel,
  logos: ExportLogos = {},
): Promise<Blob> {
  const ExcelJS = (await import('exceljs')).default
  const wb = new ExcelJS.Workbook()
  wb.creator = 'SupplierDev'
  wb.created = new Date()

  const ws = wb.addWorksheet((model.title || 'Agenda').slice(0, 28), {
    pageSetup: {
      orientation: 'landscape',
      fitToPage: true,
      fitToWidth: 1,
      fitToHeight: 0,
      margins: { left: 0.5, right: 0.5, top: 0.5, bottom: 0.5, header: 0.3, footer: 0.3 },
    },
  })

  // Time, Subject, Duration, Responsible, Participants, Info
  ws.columns = [{ width: 16 }, { width: 38 }, { width: 12 }, { width: 22 }, { width: 24 }, { width: 40 }]

  let rowCursor = 1

  // Place a logo at a column, preserving its aspect ratio within a max box.
  const placeLogo = (base64: string, col: number) => {
    const imgId = wb.addImage({ base64, extension: 'png' })
    const size = pngSize(base64)
    const maxW = 130
    const maxH = 44
    let width = maxW
    let height = maxH
    if (size) {
      const ratio = Math.min(maxW / size.width, maxH / size.height)
      width = Math.round(size.width * ratio)
      height = Math.round(size.height * ratio)
    }
    ws.addImage(imgId, { tl: { col, row: 0 }, ext: { width, height } })
  }
  const hostBase64 = logos.hostLogoPng ? dataUrlToBase64(logos.hostLogoPng) : null
  if (hostBase64) placeLogo(hostBase64, 0)
  const supplierLogos = (logos.supplierLogoPngs ?? []).slice(0, 2)
  supplierLogos.forEach((png, idx) => placeLogo(dataUrlToBase64(png), 4 + idx))
  if (hostBase64 || supplierLogos.length > 0) {
    ws.getRow(1).height = 40
    rowCursor = 2
  }

  const titleRow = ws.getRow(rowCursor)
  titleRow.getCell(1).value = model.title
  titleRow.getCell(1).font = { bold: true, size: 16, color: { argb: PETROL } }
  ws.mergeCells(rowCursor, 1, rowCursor, COLUMN_COUNT)
  rowCursor += 1

  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
    const row = ws.getRow(rowCursor)
    row.getCell(1).value = key
    row.getCell(1).font = { bold: true }
    row.getCell(2).value = value
    ws.mergeCells(rowCursor, 2, rowCursor, COLUMN_COUNT)
    rowCursor += 1
  }

  const renderParticipants = (heading: string, people: AgendaExportModel['hostParticipants']) => {
    if (people.length === 0) return
    const headingRow = ws.getRow(rowCursor)
    headingRow.getCell(1).value = heading
    headingRow.getCell(1).font = { bold: true, color: { argb: PETROL } }
    rowCursor += 1
    for (const person of people) {
      const personRow = ws.getRow(rowCursor)
      personRow.getCell(1).value = person.name
      personRow.getCell(2).value = [person.company, person.department, person.role].filter(Boolean).join(' · ')
      ws.mergeCells(rowCursor, 2, rowCursor, 5)
      personRow.getCell(6).value = [person.email, person.comment].filter(Boolean).join(' · ')
      rowCursor += 1
    }
  }
  renderParticipants(model.labels.hostParticipants, model.hostParticipants)
  renderParticipants(model.labels.supplierParticipants, model.supplierParticipants)

  rowCursor += 1

  for (const day of model.days) {
    const dayRow = ws.getRow(rowCursor)
    const dayHeadingText = [day.heading, day.dateLabel].filter(Boolean).join(' — ')
    dayRow.getCell(1).value = day.isTravelDay ? `${dayHeadingText} ✈` : dayHeadingText
    dayRow.getCell(1).font = { bold: true, size: 12, color: { argb: WHITE } }
    dayRow.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: PETROL } }
    ws.mergeCells(rowCursor, 1, rowCursor, COLUMN_COUNT)
    rowCursor += 1

    const headerRow = ws.getRow(rowCursor)
    const headers = [
      model.columns.time,
      model.columns.subject,
      model.columns.duration,
      model.columns.responsible,
      model.columns.participants,
      model.columns.info,
    ]
    headers.forEach((header, index) => {
      const cell = headerRow.getCell(index + 1)
      cell.value = header
      cell.font = { bold: true }
      cell.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: PETROL_SOFT } }
      cell.border = { bottom: { style: 'thin', color: { argb: 'FFC1C5CB' } } }
    })
    rowCursor += 1

    for (const row of day.rows) {
      const r = ws.getRow(rowCursor)
      r.getCell(1).value = row.time
      r.getCell(2).value = row.subject
      r.getCell(3).value = row.duration
      r.getCell(4).value = row.responsible
      r.getCell(5).value = row.participants
      r.getCell(6).value = row.info
      r.alignment = { vertical: 'top', wrapText: true }
      if (row.color.toUpperCase() !== '#FFFFFF') {
        const argb = hexToArgb(row.color)
        const fontArgb = isLight(row.color) ? 'FF282828' : 'FFFFFFFF'
        for (let col = 1; col <= COLUMN_COUNT; col += 1) {
          const cell = r.getCell(col)
          cell.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb } }
          cell.font = { color: { argb: fontArgb } }
        }
      }
      rowCursor += 1
    }
    rowCursor += 1
  }

  ws.pageSetup.printArea = `A1:F${Math.max(1, rowCursor)}`

  const buffer = await wb.xlsx.writeBuffer()
  return new Blob([buffer], {
    type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
  })
}
