'use client'

// ─── Types ────────────────────────────────────────────────────────────────────

export interface ExportRow {
  label: string
  value: string | number
}

export interface ExportTable {
  headers: string[]
  // C17-Fix (Wertstrom P7): `number` is now an allowed cell type — a
  // producer that stringifies a numeric field before it ever reaches this
  // type forces exportToXlsx's `ws.addRow(...)` (ExcelJS) to write a TEXT
  // cell (no right-align, no SUM()/AVERAGE(), the "number stored as text"
  // warning triangle) for what should be a real numeric cell. Both other
  // renderers already handle a numeric cell fine: exportToPdf always does
  // `String(cell)` before drawing text, and exportToPptx's `tableRows` is
  // cast through `unknown` before reaching pptxgenjs (see this file's own
  // render functions) — so this widening is a safe, backward-compatible
  // superset (every existing `string[][]` producer stays valid unchanged).
  rows: (string | number)[][]
}

export interface ExportSection {
  title: string
  items?: ExportRow[]
  table?: ExportTable
  text?: string
}

export interface ExportConfig {
  title: string
  subtitle?: string
  author?: string
  date?: string
  sections: ExportSection[]
  fileName: string
  /**
   * Company / brand name shown in PDF/PPTX headers, footers, and document
   * metadata. Tenants override via `getActiveBranding()` (see
   * `lib/branding/engine.ts`). Defaults to a neutral product name; the
   * product core never names a specific customer.
   */
  companyName?: string
  /** Footer line under the company name. Defaults to `companyName`. */
  brandFooter?: string
}

const DEFAULT_BRAND = 'Supplier Pulse'

// ─── PDF (jsPDF 4.x) ─────────────────────────────────────────────────────────

export async function exportToPdf(config: ExportConfig): Promise<Blob> {
  const { jsPDF } = await import('jspdf')
  const doc = new jsPDF({ orientation: 'portrait', unit: 'mm', format: 'a4' })

  const BRAND_PRIMARY = 'var(--primary)'
  const BRAND_DARK    = '#003D6B'
  const MUTED         = '#6B7A8D'
  const W = 210
  const MARGIN = 14
  const CONTENT_W = W - MARGIN * 2
  const brand = config.companyName ?? DEFAULT_BRAND
  const footer = config.brandFooter ?? brand

  let y = 0

  // Header bar
  doc.setFillColor(0, 61, 107) // #003D6B
  doc.rect(0, 0, W, 28, 'F')

  doc.setFont('helvetica', 'normal')
  doc.setFontSize(8)
  doc.setTextColor(255, 255, 255)
  doc.text(brand, MARGIN, 10)

  doc.setFont('helvetica', 'bold')
  doc.setFontSize(16)
  doc.text(config.title, MARGIN, 21)

  if (config.subtitle) {
    doc.setFont('helvetica', 'normal')
    doc.setFontSize(9)
    doc.setTextColor(200, 220, 235)
    doc.text(config.subtitle, W - MARGIN, 21, { align: 'right' })
  }

  y = 36

  // Meta row
  if (config.author || config.date) {
    doc.setFontSize(8)
    doc.setTextColor(107, 122, 141)
    const meta = [config.author, config.date].filter(Boolean).join(' · ')
    doc.text(meta, MARGIN, y)
    y += 6
  }

  // Sections
  for (const section of config.sections) {
    if (y > 270) {
      doc.addPage()
      y = 14
    }

    // Section title
    doc.setFont('helvetica', 'bold')
    doc.setFontSize(10)
    doc.setTextColor(0, 61, 107)
    doc.text(section.title.toUpperCase(), MARGIN, y)
    doc.setDrawColor(0, 102, 177)
    doc.setLineWidth(0.4)
    doc.line(MARGIN, y + 1.5, MARGIN + CONTENT_W, y + 1.5)
    y += 7

    // Key-value items
    if (section.items && section.items.length > 0) {
      for (const item of section.items) {
        if (y > 275) { doc.addPage(); y = 14 }
        doc.setFont('helvetica', 'normal')
        doc.setFontSize(8)
        doc.setTextColor(107, 122, 141)
        doc.text(item.label + ':', MARGIN, y)
        doc.setTextColor(28, 28, 28)
        doc.setFont('helvetica', 'bold')
        doc.text(String(item.value), MARGIN + 55, y)
        y += 5
      }
      y += 3
    }

    // Text paragraph
    if (section.text) {
      doc.setFont('helvetica', 'normal')
      doc.setFontSize(8.5)
      doc.setTextColor(28, 28, 28)
      const lines = doc.splitTextToSize(section.text, CONTENT_W)
      for (const line of lines) {
        if (y > 275) { doc.addPage(); y = 14 }
        doc.text(line, MARGIN, y)
        y += 5
      }
      y += 3
    }

    // Table
    if (section.table) {
      const { headers, rows } = section.table
      const colW = CONTENT_W / headers.length

      // Header row
      doc.setFillColor(247, 249, 251)
      doc.rect(MARGIN, y - 4, CONTENT_W, 7, 'F')
      doc.setFont('helvetica', 'bold')
      doc.setFontSize(7.5)
      doc.setTextColor(107, 122, 141)
      headers.forEach((h, i) => {
        doc.text(h, MARGIN + i * colW + 2, y)
      })
      y += 4

      // Data rows
      doc.setFont('helvetica', 'normal')
      doc.setFontSize(7.5)
      for (let ri = 0; ri < rows.length; ri++) {
        if (y > 275) { doc.addPage(); y = 14 }
        const row = rows[ri]
        if (ri % 2 === 0) {
          doc.setFillColor(252, 253, 254)
          doc.rect(MARGIN, y - 3.5, CONTENT_W, 5.5, 'F')
        }
        doc.setTextColor(28, 28, 28)
        row.forEach((cell, ci) => {
          const truncated = String(cell).slice(0, 35)
          doc.text(truncated, MARGIN + ci * colW + 2, y)
        })
        y += 5.5
      }
      y += 4
    }

    y += 2
  }

  // jsPDF exposes getNumberOfPages() via the internal API, which is not in the
  // official TypeScript definitions (pptxgenjs limitation). The cast is narrowed
  // to the minimal required shape to preserve type safety elsewhere.
  // tdd-guard:skip — comment-only, no logic change
  interface JsPdfInternal { getNumberOfPages(): number }
  const pageCount = (doc.internal as unknown as JsPdfInternal).getNumberOfPages()
  for (let p = 1; p <= pageCount; p++) {
    doc.setPage(p)
    doc.setFont('helvetica', 'normal')
    doc.setFontSize(7)
    doc.setTextColor(107, 122, 141)
    doc.text(`Seite ${p} / ${pageCount}`, W - MARGIN, 292, { align: 'right' })
    doc.text(footer, MARGIN, 292)
  }

  return doc.output('blob')
}

// ─── PowerPoint (pptxgenjs 4.x) ──────────────────────────────────────────────

export async function exportToPptx(config: ExportConfig): Promise<Blob> {
  const PptxGenJS = (await import('pptxgenjs')).default
  const prs = new PptxGenJS()

  const brand = config.companyName ?? DEFAULT_BRAND
  prs.layout = 'LAYOUT_WIDE'
  prs.author = config.author ?? brand
  prs.company = brand
  prs.subject = config.subtitle ?? config.title

  // Title slide
  const titleSlide = prs.addSlide()
  titleSlide.background = { color: '003D6B' }

  titleSlide.addShape(prs.ShapeType.rect, {
    x: 0, y: 4.2, w: '100%', h: 0.5,
    fill: { color: '0066B1' },
    line: { color: '0066B1', width: 0 },
  })

  titleSlide.addText(brand, {
    x: 0.5, y: 0.4, w: 9, h: 0.4,
    fontSize: 10, color: 'CCE0F0', fontFace: 'Calibri', bold: false,
  })

  titleSlide.addText(config.title, {
    x: 0.5, y: 1.1, w: 11, h: 1.2,
    fontSize: 36, color: 'FFFFFF', fontFace: 'Calibri', bold: true,
  })

  if (config.subtitle) {
    titleSlide.addText(config.subtitle, {
      x: 0.5, y: 2.4, w: 11, h: 0.5,
      fontSize: 16, color: 'B3D1E8', fontFace: 'Calibri',
    })
  }

  const meta = [config.author, config.date].filter(Boolean).join(' · ')
  if (meta) {
    titleSlide.addText(meta, {
      x: 0.5, y: 4.8, w: 11, h: 0.35,
      fontSize: 10, color: '6B8DA8', fontFace: 'Calibri',
    })
  }

  // Section slides
  for (const section of config.sections) {
    const slide = prs.addSlide()
    slide.background = { color: 'F7F9FB' }

    // Top bar
    slide.addShape(prs.ShapeType.rect, {
      x: 0, y: 0, w: '100%', h: 0.7,
      fill: { color: '003D6B' },
      line: { color: '003D6B', width: 0 },
    })

    slide.addText(section.title, {
      x: 0.4, y: 0.05, w: 10, h: 0.6,
      fontSize: 14, color: 'FFFFFF', fontFace: 'Calibri', bold: true,
    })

    let contentY = 0.9

    // Key-value pairs as two-col table
    if (section.items && section.items.length > 0) {
      const rows = [
        [
          { text: 'Kennzahl', options: { bold: true, color: '003D6B', fill: { color: 'E6F0F8' } } },
          { text: 'Wert', options: { bold: true, color: '003D6B', fill: { color: 'E6F0F8' } } },
        ],
        ...section.items.map(item => [
          { text: item.label, options: { color: '1C1C1C' } },
          { text: String(item.value), options: { color: '0066B1', bold: true } },
        ]),
      ]

      // pptxgenjs TableCell type does not accept inline object literals with
      // mixed options — narrow via Parameters utility to preserve slide type safety.
      slide.addTable(rows as unknown as Parameters<typeof slide.addTable>[0], {
        x: 0.4, y: contentY, w: 11.5,
        fontSize: 10, fontFace: 'Calibri',
        border: { pt: 0.5, color: 'E0E6ED' },
        rowH: 0.32,
      })

      contentY += section.items.length * 0.32 + 0.5 + 0.4
    }

    // Text
    if (section.text) {
      slide.addText(section.text, {
        x: 0.4, y: contentY, w: 11.5, h: 1.5,
        fontSize: 10, color: '1C1C1C', fontFace: 'Calibri',
        wrap: true, valign: 'top',
      })
      contentY += 1.7
    }

    // Full table
    if (section.table) {
      const { headers, rows: dataRows } = section.table
      const tableRows = [
        headers.map(h => ({
          text: h,
          options: { bold: true, color: '003D6B', fill: { color: 'E6F0F8' } },
        })),
        ...dataRows.map((row, ri) =>
          row.map(cell => ({
            text: cell,
            options: { color: '1C1C1C', fill: { color: ri % 2 === 0 ? 'FFFFFF' : 'F7F9FB' } },
          }))
        ),
      ]

      const remaining = 5.5 - contentY
      // pptxgenjs TableCell type does not accept inline object literals with
      // mixed options — narrow via Parameters utility to preserve slide type safety.
      slide.addTable(tableRows as unknown as Parameters<typeof slide.addTable>[0], {
        x: 0.4, y: contentY, w: 11.5,
        h: Math.max(0.5, remaining),
        fontSize: 9, fontFace: 'Calibri',
        border: { pt: 0.5, color: 'E0E6ED' },
        rowH: 0.28,
        autoPage: true,
      })
    }

    // Page num in footer
    slide.addText(`${config.title} · ${brand}`, {
      x: 0.4, y: 5.55, w: 10, h: 0.25,
      fontSize: 7, color: '6B7A8D', fontFace: 'Calibri',
    })
  }

  const blob = await prs.write({ outputType: 'blob' }) as Blob
  return blob
}

// ─── Excel (ExcelJS) ─────────────────────────────────────────────────────────

export async function exportToXlsx(config: ExportConfig): Promise<Blob> {
  const ExcelJS = (await import('exceljs')).default
  const wb = new ExcelJS.Workbook()
  wb.creator = config.author ?? config.companyName ?? DEFAULT_BRAND
  wb.created = new Date()

  const BMW_BLUE  = 'FF0066B1'
  const BMW_DARK  = 'FF003D6B'
  const LIGHT_BG  = 'FFE6F0F8'
  const BORDER_C  = 'FFE0E6ED'
  const MUTED_TXT = 'FF6B7A8D'

  for (const section of config.sections) {
    const safeTitle = section.title.slice(0, 31).replace(/[\\/*?[\]:]/g, '_')
    const ws = wb.addWorksheet(safeTitle)

    // Column widths
    ws.columns = Array.from({ length: 10 }, () => ({ width: 22 }))

    // Section header
    ws.addRow([section.title])
    const titleRow = ws.lastRow!
    titleRow.height = 22
    titleRow.getCell(1).font = { bold: true, size: 13, color: { argb: 'FFFFFFFF' } }
    titleRow.getCell(1).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: BMW_DARK } }
    titleRow.getCell(1).alignment = { vertical: 'middle' }
    ws.mergeCells(titleRow.number, 1, titleRow.number, Math.max(2, (section.table?.headers.length ?? 2)))

    ws.addRow([])

    // Key-value pairs
    if (section.items && section.items.length > 0) {
      for (const item of section.items) {
        ws.addRow([item.label, item.value])
        const row = ws.lastRow!
        row.getCell(1).font = { color: { argb: MUTED_TXT } }
        row.getCell(2).font = { bold: true, color: { argb: BMW_BLUE } }
      }
      ws.addRow([])
    }

    // Text
    if (section.text) {
      ws.addRow([section.text])
      const row = ws.lastRow!
      row.getCell(1).alignment = { wrapText: true }
      ws.addRow([])
    }

    // Table
    if (section.table) {
      const { headers, rows } = section.table

      // Header row
      ws.addRow(headers)
      const hRow = ws.lastRow!
      hRow.height = 18
      hRow.eachCell(cell => {
        cell.font = { bold: true, color: { argb: BMW_DARK } }
        cell.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: LIGHT_BG } }
        cell.border = {
          bottom: { style: 'thin', color: { argb: BORDER_C } },
          top:    { style: 'thin', color: { argb: BORDER_C } },
        }
      })

      // Data rows
      for (let ri = 0; ri < rows.length; ri++) {
        ws.addRow(rows[ri])
        const row = ws.lastRow!
        if (ri % 2 === 1) {
          row.eachCell(cell => {
            cell.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFF7F9FB' } }
          })
        }
      }
    }
  }

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

// ─── Download helper ──────────────────────────────────────────────────────────

export async function downloadBlob(blob: Blob, filename: string): Promise<void> {
  const { saveAs } = await import('file-saver')
  saveAs(blob, filename)
}
