import { formatCurrency, formatMinutes, formatSimulationTimestamp } from '@/lib/format'
import type { SimulationResult, Process, ActivitySimResult, Resource, Activity } from '@/domain/types'
import { PDF_COLORS, type DocLike } from './pdf-sections-shared'

// Re-exportar DocLike para compatibilidad de imports existentes (pdf-sections-roi, tests)
export type { DocLike } from './pdf-sections-shared'

// Colores locales para página 1 de PDFs Actual/Automatizado (sin gradiente — Etapa 8)
const _SC = {
  orange:       [245, 152, 69]  as [number, number, number],  // #F59845
  orangeLight:  [254, 243, 226] as [number, number, number],  // #FEF3E2
  orangeDarker: [146, 64, 14]   as [number, number, number],  // #92400E
  orangeDark:   [180, 83, 9]    as [number, number, number],  // #B45309
  metaBg:       [250, 251, 252] as [number, number, number],  // #FAFBFC
}

// Unidades: mm. A4 = 210 × 297mm, márgenes 20mm, área útil 170 × 257mm
// PDF.blue eliminado en Etapa 4 — usar PDF_COLORS.inqOrange del módulo compartido
export const PDF = {
  pageW: 210, pageH: 297,
  margin: 20,
  contentW: 170,
  inqOrange: PDF_COLORS.inqOrange,
  slate900: [15, 23, 42] as [number, number, number],
  slate700: [51, 65, 85] as [number, number, number],
  slate500: [100, 116, 139] as [number, number, number],
  slate200: [226, 232, 240] as [number, number, number],
  slate50: [248, 250, 252] as [number, number, number],
  heatLow: [16, 185, 129] as [number, number, number],
  heatMid: [245, 158, 11] as [number, number, number],
  heatHigh: [239, 68, 68] as [number, number, number],
}

export function drawHeader(doc: DocLike, process: Process, simulatedAt: number): number {
  let y = PDF.margin

  // Nombre del proceso
  doc.setFont('helvetica', 'bold')
  doc.setFontSize(20)
  doc.setTextColor(...PDF.slate900)
  doc.text(process.name, PDF.margin, y)
  y += 8

  // Cliente + fecha + moneda
  const { date, time } = formatSimulationTimestamp(simulatedAt)
  const subtitle = [
    process.clientName ? `Cliente: ${process.clientName}` : null,
    `Simulado el ${date} a las ${time}`,
    `Moneda: ${process.currency}`,
  ].filter(Boolean).join('  ·  ')

  doc.setFont('helvetica', 'normal')
  doc.setFontSize(9)
  doc.setTextColor(...PDF.slate500)
  doc.text(subtitle, PDF.margin, y)
  y += 5

  // Línea separadora
  doc.setDrawColor(...PDF.slate200)
  doc.setLineWidth(0.3)
  doc.line(PDF.margin, y, PDF.margin + PDF.contentW, y)
  y += 5

  return y
}

export function drawKpiCards(
  doc: DocLike,
  result: SimulationResult,
  currency: string,
  startY: number
): number {
  const cardW = 80, cardH = 24, gap = 10
  const col1 = PDF.margin, col2 = PDF.margin + cardW + gap

  const cards = [
    { label: 'COSTO TOTAL ESPERADO', value: formatCurrency(result.totalCost, currency), accent: true },
    { label: 'COSTO DIRECTO / OVERHEAD', value: `${formatCurrency(result.totalDirectCost, currency)} / ${formatCurrency(result.totalIndirectCost, currency)}`, accent: false },
    { label: 'TIEMPO TOTAL ESPERADO', value: formatMinutes(result.totalTimeMinutes), accent: false },
    { label: 'ACTIVIDADES COSTEADAS', value: String(result.perActivity.length), accent: false },
  ]

  let maxY = startY

  cards.forEach((card, idx) => {
    const x = idx % 2 === 0 ? col1 : col2
    const y = idx < 2 ? startY : startY + cardH + 4

    // Fondo
    doc.setFillColor(...PDF.slate50)
    doc.roundedRect(x, y, cardW, cardH, 2, 2, 'F')

    // Borde
    doc.setDrawColor(...PDF.slate200)
    doc.setLineWidth(0.2)
    doc.roundedRect(x, y, cardW, cardH, 2, 2, 'S')

    // Label pequeño
    doc.setFont('helvetica', 'normal')
    doc.setFontSize(6.5)
    doc.setTextColor(...PDF.slate500)
    doc.text(card.label, x + 4, y + 6)

    // Valor grande
    doc.setFont('helvetica', 'bold')
    doc.setFontSize(card.value.length > 16 ? 9 : 12)
    doc.setTextColor(...(card.accent ? PDF.inqOrange : PDF.slate900))
    doc.text(card.value, x + 4, y + 16)

    maxY = Math.max(maxY, y + cardH)
  })

  return maxY + 6
}

export function drawHeatmapImage(
  doc: DocLike,
  imageDataUrl: string | null,
  startY: number
): number {
  if (!imageDataUrl) return startY

  // Usar dimensiones dinámicas — funciona en portrait (210mm) y landscape (297mm)
  const pageW = doc.internal.pageSize.getWidth()
  const pageH = doc.internal.pageSize.getHeight()
  const imgW = pageW - 2 * PDF.margin
  // Altura: proporción ~2.2:1 del canvas BPMN, limitada por espacio disponible hasta el footer
  const maxH = pageH - startY - PDF.margin - 20  // 20mm reservado para footer
  const imgH = Math.min(imgW / 2.2, maxH)

  const x = PDF.margin
  if (startY + imgH > pageH - PDF.margin - 10) {
    doc.addPage()
    startY = PDF.margin
  }

  // Borde sutil
  doc.setDrawColor(...PDF.slate200)
  doc.setLineWidth(0.2)
  doc.rect(x, startY, imgW, imgH, 'S')

  doc.addImage(imageDataUrl, 'JPEG', x, startY, imgW, imgH)
  return startY + imgH + 4
}

export function drawHeatmapLegend(doc: DocLike, startY: number): number {
  const pageW = doc.internal.pageSize.getWidth()
  const x = PDF.margin, barW = pageW - 2 * PDF.margin, barH = 4
  const labelY = startY + barH + 3.5

  doc.setFontSize(7)
  doc.setFont('helvetica', 'normal')

  // Etiqueta izquierda
  doc.setTextColor(...PDF.heatLow)
  doc.text('Bajo costo', x, labelY)

  // Barra de gradiente: dibujada como N segmentos de colores
  const steps = 40
  const segW = barW / steps
  for (let i = 0; i < steps; i++) {
    const t = i / (steps - 1)
    let r: number, g: number, b: number
    if (t <= 0.5) {
      const lt = t * 2
      r = Math.round(PDF.heatLow[0] + (PDF.heatMid[0] - PDF.heatLow[0]) * lt)
      g = Math.round(PDF.heatLow[1] + (PDF.heatMid[1] - PDF.heatLow[1]) * lt)
      b = Math.round(PDF.heatLow[2] + (PDF.heatMid[2] - PDF.heatLow[2]) * lt)
    } else {
      const lt = (t - 0.5) * 2
      r = Math.round(PDF.heatMid[0] + (PDF.heatHigh[0] - PDF.heatMid[0]) * lt)
      g = Math.round(PDF.heatMid[1] + (PDF.heatHigh[1] - PDF.heatMid[1]) * lt)
      b = Math.round(PDF.heatMid[2] + (PDF.heatHigh[2] - PDF.heatMid[2]) * lt)
    }
    doc.setFillColor(r, g, b)
    doc.rect(x + i * segW, startY, segW + 0.1, barH, 'F')
  }

  // Etiqueta derecha
  doc.setTextColor(...PDF.heatHigh)
  doc.text('Alto costo', x + barW, labelY, { align: 'right' } as any)

  return labelY + 3
}

export function drawAnalysisSection(
  doc: DocLike,
  result: SimulationResult,
  currency: string,
  startY: number
): number {
  let y = startY
  const m = PDF.margin, cW = PDF.contentW

  // Título uppercase naranja oscuro
  doc.setFont('helvetica', 'bold')
  doc.setFontSize(11)
  doc.setTextColor(..._SC.orangeDarker)
  doc.text('ANÁLISIS DE COMPOSICIÓN', m, y)
  y += 5

  doc.setDrawColor(..._SC.orange)
  doc.setLineWidth(0.5)
  doc.line(m, y, m + cW, y)
  doc.setLineWidth(0.2)
  y += 7

  doc.setFont('helvetica', 'normal')
  doc.setFontSize(9)
  doc.setTextColor(...PDF_COLORS.textPrimary)

  const directPct = result.totalCost > 0
    ? ((result.totalDirectCost / result.totalCost) * 100).toFixed(1) : '0'
  const indirectPct = result.totalCost > 0
    ? ((result.totalIndirectCost / result.totalCost) * 100).toFixed(1) : '0'

  const compositionText = `Composición del costo: ${directPct}% directo (${formatCurrency(result.totalDirectCost, currency)}) · ${indirectPct}% overhead (${formatCurrency(result.totalIndirectCost, currency)})`
  const compositionLines = doc.splitTextToSize(compositionText, cW)
  doc.text(compositionLines, m, y)
  y += compositionLines.length * 4.5 + 4

  const top3 = result.perActivity.slice(0, 3)
  const top3Text = top3.map((a, i) => `${i + 1}. ${a.activityName} (${a.percentOfTotal.toFixed(1)}% - ${formatCurrency(a.expectedTotalCost, currency)})`).join('  ')
  doc.setTextColor(...PDF_COLORS.textSecondary)
  const top3Lines = doc.splitTextToSize(`Top 3 actividades por costo: ${top3Text}`, cW)
  doc.text(top3Lines, m, y)
  y += top3Lines.length * 4.5 + 2

  if (result.perResource.length > 0) {
    const topResource = [...result.perResource].sort((a, b) => b.totalCost - a.totalCost)[0]
    const resourceLine = doc.splitTextToSize(
      `Recurso principal: "${topResource.resourceName}" — ${formatCurrency(topResource.totalCost, currency)}`,
      cW
    )
    doc.text(resourceLine, m, y)
    y += resourceLine.length * 4.5
  } else {
    doc.setTextColor(...PDF_COLORS.textTertiary)
    doc.text('Sin recursos asignados (costos fijos por actividad)', m, y)
    y += 5
  }

  return y + 2
}

export function drawMethodologySection(
  doc: DocLike,
  process: Process,
  startY: number
): number {
  let y = startY
  const m = PDF.margin, cW = PDF.contentW
  const boxPad = 6

  // Título uppercase naranja oscuro
  doc.setFont('helvetica', 'bold')
  doc.setFontSize(11)
  doc.setTextColor(..._SC.orangeDarker)
  doc.text('NOTA METODOLÓGICA', m, y)
  y += 5

  doc.setDrawColor(..._SC.orange)
  doc.setLineWidth(0.5)
  doc.line(m, y, m + cW, y)
  doc.setLineWidth(0.2)
  y += 8

  // Caja contenedora slate-50 con border-left gris (mismo patrón que ROI Etapa 7)
  const sections = [
    {
      title: 'Costo total:',
      body: `Costo total = SUM(actividades) costo_directo_esperado + costo_indirecto_esperado.`,
    },
    {
      title: 'Costo directo por actividad:',
      body: `(costo_fijo + SUM(recurso x costo_hora x tiempo x utilizacion / 60)) x probabilidad_ejecucion.`,
    },
    {
      title: 'Costo indirecto:',
      body: `costo_directo_total x overhead_global (${(process.overheadPercentage * 100).toFixed(0)}%).`,
    },
    {
      title: 'Probabilidades de ejecución:',
      body: 'Calculadas mediante propagacion hacia adelante desde el StartEvent, considerando gateways XOR y AND. Modelo determinístico agregado.',
    },
  ]

  let boxHeight = boxPad * 2
  for (const s of sections) {
    const bodyLines = doc.splitTextToSize(s.body, cW - boxPad * 2 - 4)
    boxHeight += 5 + bodyLines.length * 4.2 + 4
  }

  doc.setFillColor(248, 250, 252)  // slate-50
  doc.rect(m, y, cW, boxHeight, 'F')
  doc.setFillColor(..._SC.metaBg)
  doc.rect(m, y, 2, boxHeight, 'F')

  let ty = y + boxPad
  const contentX = m + boxPad + 3
  for (const s of sections) {
    doc.setFont('helvetica', 'bold')
    doc.setFontSize(9)
    doc.setTextColor(...PDF_COLORS.textPrimary)
    doc.text(s.title, contentX, ty)
    ty += 5

    doc.setFont('helvetica', 'normal')
    doc.setFontSize(8.5)
    doc.setTextColor(...PDF_COLORS.textSecondary)
    const lines = doc.splitTextToSize(s.body, cW - boxPad * 2 - 4)
    doc.text(lines, contentX, ty)
    ty += lines.length * 4.2 + 4
  }

  return y + boxHeight + 4
}

// ─── Página 1 Actual/Automatizado: header denso + metadata + KPI grid ─────────
// Sin gradiente — jerarquía visual: ROI es el reporte principal (Etapa 8).

export function drawScenarioPage1(
  doc: DocLike,
  tab: 'actual' | 'automatizado',
  process: Process,
  simulatedAt: number,
  result: SimulationResult,
  currency: string
): number {
  const pageW = doc.internal.pageSize.getWidth()
  const m = 20, cW = pageW - 2 * m
  let y = m
  y = _drawScenarioDenseHeader(doc, pageW, m, cW, tab, y)
  y = _drawScenarioMetadataStrip(doc, process, simulatedAt, m, cW, y)
  y = drawScenarioKpiGrid(doc, result, currency, m, cW, y)
  return y
}

function _drawScenarioDenseHeader(
  doc: DocLike, pageW: number, m: number, cW: number,
  tab: 'actual' | 'automatizado', y: number
): number {
  const right = pageW - m
  const subtitle = tab === 'actual'
    ? 'ANÁLISIS DE COSTOS — ESCENARIO ACTUAL'
    : 'ANÁLISIS DE COSTOS — ESCENARIO AUTOMATIZADO'

  doc.setFont('helvetica', 'bold')
  doc.setFontSize(22)
  doc.setTextColor(..._SC.orange)
  doc.text('InQ ROI', m, y)

  doc.setFont('helvetica', 'normal')
  doc.setFontSize(9)
  doc.setTextColor(...PDF_COLORS.textDisabled)
  doc.text('UN PRODUCTO DE', right, y, { align: 'right' } as Record<string, unknown>)
  y += 9

  doc.setFont('helvetica', 'normal')
  doc.setFontSize(9)
  doc.setTextColor(...PDF_COLORS.textDisabled)
  doc.text(subtitle, m, y)

  doc.setFont('helvetica', 'bold')
  doc.setFontSize(16)
  doc.setTextColor(...PDF_COLORS.textSecondary)
  doc.text('InQ', right, y, { align: 'right' } as Record<string, unknown>)
  y += 6

  doc.setFont('helvetica', 'normal')
  doc.setFontSize(9)
  doc.setTextColor(...PDF_COLORS.textTertiary)
  doc.text('InQuality', right, y, { align: 'right' } as Record<string, unknown>)
  y += 10

  doc.setDrawColor(..._SC.orange)
  doc.setLineWidth(0.8)
  doc.line(m, y, m + cW, y)
  doc.setLineWidth(0.2)
  y += 10

  return y
}

function _drawScenarioMetadataStrip(
  doc: DocLike, process: Process, simulatedAt: number,
  m: number, cW: number, y: number
): number {
  const h = 16, r = 2
  doc.setFillColor(..._SC.metaBg)
  doc.roundedRect(m, y, cW, h, r, r, 'F')

  const { date } = formatSimulationTimestamp(simulatedAt)
  const col2 = m + cW * 0.5
  const col3 = m + cW * 0.75

  const cells = [
    { label: 'PROCESO', value: process.name, x: m + 4 },
    { label: 'FECHA', value: date, x: col2 + 4 },
    { label: 'MONEDA', value: process.currency, x: col3 + 4 },
  ]

  for (const cell of cells) {
    doc.setFont('helvetica', 'normal')
    doc.setFontSize(7)
    doc.setTextColor(...PDF_COLORS.textDisabled)
    doc.text(cell.label, cell.x, y + 5)

    doc.setFont('helvetica', 'bold')
    doc.setFontSize(9)
    doc.setTextColor(...PDF_COLORS.textPrimary)
    const val = cell.value.length > 28 ? cell.value.slice(0, 26) + '...' : cell.value
    doc.text(val, cell.x, y + 12)
  }

  return y + h + 6
}

export function drawScenarioKpiGrid(
  doc: DocLike,
  result: SimulationResult,
  currency: string,
  m: number,
  cW: number,
  startY: number
): number {
  const cardW = (cW - 4) / 2
  const cardH = 26
  const gapX = 4, gapY = 4
  const r = 2

  const directPct = result.totalCost > 0
    ? (result.totalDirectCost / result.totalCost * 100).toFixed(1) : '0'

  const cards = [
    { label: 'COSTO TOTAL ESPERADO',    value: formatCurrency(result.totalCost, currency),           sub: '',                  col: 0, row: 0 },
    { label: 'COSTO DIRECTO / OVERHEAD', value: formatCurrency(result.totalDirectCost, currency),    sub: `${directPct}% directo`, col: 1, row: 0 },
    { label: 'TIEMPO TOTAL ESPERADO',   value: formatMinutes(result.totalTimeMinutes),               sub: '',                  col: 0, row: 1 },
    { label: 'ACTIVIDADES COSTEADAS',   value: String(result.perActivity.length),                    sub: '',                  col: 1, row: 1 },
  ]

  let maxY = startY
  for (const card of cards) {
    const cx = m + card.col * (cardW + gapX)
    const cy = startY + card.row * (cardH + gapY)

    doc.setFillColor(..._SC.orangeLight)
    doc.roundedRect(cx, cy, cardW, cardH, r, r, 'F')

    doc.setFont('helvetica', 'bold')
    doc.setFontSize(7)
    doc.setTextColor(..._SC.orangeDarker)
    doc.text(card.label, cx + 5, cy + 7)

    doc.setFont('helvetica', 'bold')
    doc.setFontSize(card.value.length > 16 ? 10 : 14)
    doc.setTextColor(...PDF_COLORS.textPrimary)
    doc.text(card.value, cx + 5, cy + 17)

    if (card.sub) {
      doc.setFont('helvetica', 'normal')
      doc.setFontSize(7.5)
      doc.setTextColor(..._SC.orangeDark)
      doc.text(card.sub, cx + 5, cy + 23)
    }

    maxY = Math.max(maxY, cy + cardH)
  }

  return maxY + 8
}

// ─── Tabla de recursos por actividad ─────────────────────────────────────────

function _fmtNum(n: number): string {
  return n.toLocaleString('es-PY', { minimumFractionDigits: 2, maximumFractionDigits: 2 })
}

export function drawResourcesSection(
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  doc: any,
  // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
  autoTable: Function,
  result: { perActivity: ActivitySimResult[] },
  resources: Resource[],
  activities: Activity[],
  currency: string,
  startY: number,
  scenario: 'actual' | 'automatizado' = 'actual'
): void {
  let y = startY
  const m = PDF.margin
  const cW = PDF.contentW

  doc.setFont('helvetica', 'bold')
  doc.setFontSize(10)
  doc.setTextColor(...PDF.slate900)
  doc.text('DESGLOSE DE RECURSOS POR ACTIVIDAD', m, y)
  y += 2
  doc.setDrawColor(...PDF.slate200)
  doc.setLineWidth(0.5)
  doc.line(m, y, m + cW, y)
  doc.setLineWidth(0.2)
  y += 5

  doc.setFont('helvetica', 'normal')
  doc.setFontSize(8)
  doc.setTextColor(...PDF.slate500)
  doc.text('Costo por ejecución, ponderado por probabilidad de ejecución de cada actividad.', m, y)
  y += 6

  const resourceMap = new Map(resources.map((r) => [r.id, r]))
  const activityMap = new Map(activities.map((a) => [a.id, a]))

  const TYPE_LABEL: Record<string, string> = {
    role: 'Rol', person: 'Persona', system: 'Sistema', equipment: 'Equipamiento', supply: 'Insumo',
  }
  const TYPE_COLOR: Record<string, [number, number, number]> = {
    role:      [255, 237, 213],
    person:    [220, 252, 231],
    system:    [219, 234, 254],
    equipment: [241, 245, 249],
    supply:    [254, 249, 195],
  }

  const RA = 'right' as const

  const tableHead = [[
    { content: 'Actividad',              styles: { cellWidth: 40 } },
    { content: 'Recurso',                styles: { cellWidth: 38 } },
    { content: 'Tipo',                   styles: { cellWidth: 20 } },
    { content: `$/h (${currency})`,      styles: { halign: RA, cellWidth: 20 } },
    { content: 'Min.',                   styles: { halign: RA, cellWidth: 14 } },
    { content: 'Uds.',                   styles: { halign: RA, cellWidth: 12 } },
    { content: `Esp. (${currency})`, styles: { halign: RA, cellWidth: 26 } },
  ]]

  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  const tableBody: any[] = []

  for (const act of result.perActivity) {
    if (act.resourceCostBreakdown.length === 0) continue

    const activityRow = activityMap.get(act.activityId)

    for (const br of act.resourceCostBreakdown) {
      const resource = resourceMap.get(br.resourceId)
      const assignment = scenario === 'automatizado'
        ? activityRow?.automatedAssignedResources?.find((a) => a.resourceId === br.resourceId)
        : activityRow?.assignedResources.find((a) => a.resourceId === br.resourceId)

      const typeName  = resource ? (TYPE_LABEL[resource.type] ?? resource.type) : '—'
      const typeColor = resource ? (TYPE_COLOR[resource.type] ?? PDF.slate50) : PDF.slate50
      const costPerHour = resource ? _fmtNum(resource.costPerHour) : '—'
      const minutes = assignment ? String(assignment.utilizationMinutes) : '—'
      const units   = assignment ? String(assignment.units) : '—'

      // Nombre de actividad repetido por fila — rowSpan no está soportado en body de autotable
      tableBody.push([
        { content: act.activityName },
        { content: br.resourceName },
        { content: typeName, styles: { fillColor: typeColor, fontStyle: 'bold', fontSize: 7 } },
        { content: costPerHour, styles: { halign: RA, font: 'courier' } },
        { content: minutes,     styles: { halign: RA, font: 'courier' } },
        { content: units,       styles: { halign: RA, font: 'courier' } },
        { content: _fmtNum(br.cost), styles: { halign: RA, font: 'courier' } },
      ])
    }

    // Fila de subtotal por actividad
    const subtotal = act.resourceCostBreakdown.reduce((s, r) => s + r.cost, 0)
    tableBody.push([
      { content: '', styles: { fillColor: [255, 248, 237] } },
      { content: 'Subtotal recursos', colSpan: 5, styles: { fontStyle: 'italic', fontSize: 7.5, fillColor: [255, 248, 237] } },
      { content: _fmtNum(subtotal), styles: { halign: RA, font: 'courier', fontStyle: 'bold', fillColor: [255, 248, 237] } },
    ])
  }

  if (tableBody.length === 0) return

  autoTable(doc, {
    head: tableHead,
    body: tableBody,
    startY: y,
    margin: { left: m, right: m },
    styles: { fontSize: 7.5, cellPadding: 2.5, overflow: 'ellipsize', lineColor: [226, 232, 240], lineWidth: 0.2 },
    headStyles: {
      fillColor: [255, 248, 237],
      textColor: [146, 64, 14],
      fontStyle: 'bold',
      fontSize: 8,
      lineColor: [245, 152, 69],
      lineWidth: 0.5,
    },
    alternateRowStyles: { fillColor: PDF.slate50 },
  })
}

export function addPageNumbers(doc: DocLike, platformName: string, generatedAt: number): void {
  const total = doc.internal.getNumberOfPages()
  const { date } = formatSimulationTimestamp(generatedAt)

  for (let i = 1; i <= total; i++) {
    doc.setPage(i)
    doc.setFont('helvetica', 'normal')
    doc.setFontSize(7)
    doc.setTextColor(180, 180, 180)
    doc.text(
      `${platformName}  ·  ${date}  ·  Página ${i} de ${total}`,
      105,
      PDF.pageH - 8,
      { align: 'center' } as any
    )
  }
}
