/**
 * Smoke tests del export PDF.
 * jsPDF + autotable se mockean porque requieren canvas/DOM completo.
 * Se verifica: llamadas al builder, metadata, nombre de archivo, no-throw.
 */
import { describe, it, expect, vi, beforeEach } from 'vitest'

// ─── Mock de jsPDF ────────────────────────────────────────────────────────────
const mockDoc = {
  setProperties: vi.fn(),
  setFont: vi.fn(),
  setFontSize: vi.fn(),
  setTextColor: vi.fn(),
  setFillColor: vi.fn(),
  setDrawColor: vi.fn(),
  setLineWidth: vi.fn(),
  text: vi.fn(),
  rect: vi.fn(),
  roundedRect: vi.fn(),
  line: vi.fn(),
  addImage: vi.fn(),
  addPage: vi.fn(),
  setPage: vi.fn(),
  save: vi.fn(),
  splitTextToSize: vi.fn().mockImplementation((text: string) => [text]),
  internal: {
    getNumberOfPages: vi.fn().mockReturnValue(3),
    pageSize: {
      getWidth: vi.fn().mockReturnValue(210),
      getHeight: vi.fn().mockReturnValue(297),
    },
  },
}

// Arrow functions no pueden ser constructoras — usar function() regular
vi.mock('jspdf', () => {
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  function MockJsPDF(this: any) { return mockDoc }
  return { jsPDF: MockJsPDF }
})

vi.mock('jspdf-autotable', () => ({
  default: vi.fn(),
}))

// ─── Fixtures ─────────────────────────────────────────────────────────────────

import type { Process, Simulation } from '@/domain/types'

const mockProcess: Process = {
  id: 'p1', name: 'Proceso de Aprobación de Crédito',
  clientName: 'Banco XYZ',
  bpmnXml: '', currency: 'USD',
  overheadPercentage: 0.2,
  annualFrequency: 1000, analysisHorizonYears: 3, automationInvestment: 0,
  createdAt: 0, updatedAt: 0,
  groupId: null, tags: [],
}

const mockSimulation: Simulation = {
  id: 'sim1', processId: 'p1',
  executedAt: new Date('2026-05-13T10:00:00Z').getTime(),
  result: {
    totalCost: 1200,
    totalDirectCost: 1000,
    totalIndirectCost: 200,
    totalTimeMinutes: 90,
    perActivity: [
      {
        activityId: 'a1', bpmnElementId: 'task1', activityName: 'Recibir solicitud',
        expectedDirectCost: 600, expectedIndirectCost: 120, expectedTotalCost: 720,
        percentOfTotal: 60, executionProbability: 1.0, expectedExecutions: 1.0,
        executionTimeMinutes: 30, resourceCostBreakdown: [],
      },
      {
        activityId: 'a2', bpmnElementId: 'task2', activityName: 'Procesar',
        expectedDirectCost: 400, expectedIndirectCost: 80, expectedTotalCost: 480,
        percentOfTotal: 40, executionProbability: 0.8, expectedExecutions: 0.8,
        executionTimeMinutes: 60, resourceCostBreakdown: [],
      },
    ],
    perResource: [],
    warnings: [],
  },
}

// ─── Tests ────────────────────────────────────────────────────────────────────

describe('exportToPdf — smoke tests', () => {
  beforeEach(() => { vi.clearAllMocks() })

  it('no lanza error con parámetros válidos y heatmap null', async () => {
    const { exportToPdf } = await import('@/lib/export/pdf-export')
    await expect(exportToPdf({
      process: mockProcess,
      simulation: mockSimulation,
      resources: [],
      heatmapImageData: null,
    })).resolves.not.toThrow()
  })

  it('llama a doc.addPage al menos una vez (estructura multi-página)', async () => {
    const { exportToPdf } = await import('@/lib/export/pdf-export')
    await exportToPdf({ process: mockProcess, simulation: mockSimulation, resources: [], heatmapImageData: null })
    // El PDF tiene al menos 2 páginas (análisis + tabla)
    expect(mockDoc.addPage).toHaveBeenCalled()
  })

  it('llama a setProperties con metadata correcta', async () => {
    const { exportToPdf } = await import('@/lib/export/pdf-export')
    await exportToPdf({ process: mockProcess, simulation: mockSimulation, resources: [], heatmapImageData: null })
    expect(mockDoc.setProperties).toHaveBeenCalledWith(expect.objectContaining({
      title: expect.stringContaining('Proceso de Aprobación de Crédito'),
      author: 'Banco XYZ',
      subject: 'Simulación de proceso BPMN',
    }))
  })

  it('llama a doc.save con nombre de archivo correcto', async () => {
    const { exportToPdf } = await import('@/lib/export/pdf-export')
    await exportToPdf({ process: mockProcess, simulation: mockSimulation, resources: [], heatmapImageData: null })
    const saveCall = mockDoc.save.mock.calls[0][0] as string
    expect(saveCall).toMatch(/proceso-de-aprobacion-de-credito/)
    expect(saveCall).toMatch(/banco-xyz/)
    expect(saveCall).toMatch(/\.pdf$/)
  })

  it('NO llama a addImage cuando heatmapImageData es null', async () => {
    const { exportToPdf } = await import('@/lib/export/pdf-export')
    await exportToPdf({ process: mockProcess, simulation: mockSimulation, resources: [], heatmapImageData: null })
    expect(mockDoc.addImage).not.toHaveBeenCalled()
  })

  it('llama a addImage cuando heatmapImageData está disponible', async () => {
    const { exportToPdf } = await import('@/lib/export/pdf-export')
    const fakeDataUrl = 'data:image/jpeg;base64,/9j/fake'
    await exportToPdf({ process: mockProcess, simulation: mockSimulation, resources: [], heatmapImageData: fakeDataUrl })
    expect(mockDoc.addImage).toHaveBeenCalledWith(fakeDataUrl, 'JPEG', expect.any(Number), expect.any(Number), expect.any(Number), expect.any(Number))
  })

  it('llama a addPageNumbers (setPage para el footer)', async () => {
    const { exportToPdf } = await import('@/lib/export/pdf-export')
    await exportToPdf({ process: mockProcess, simulation: mockSimulation, resources: [], heatmapImageData: null })
    // addPageNumbers itera setPage para cada página
    expect(mockDoc.setPage).toHaveBeenCalled()
  })

  it('llama a autoTable con head que contiene la moneda', async () => {
    const autoTable = (await import('jspdf-autotable')).default as ReturnType<typeof vi.fn>
    const { exportToPdf } = await import('@/lib/export/pdf-export')
    await exportToPdf({ process: mockProcess, simulation: mockSimulation, resources: [], heatmapImageData: null })
    expect(autoTable).toHaveBeenCalledWith(
      expect.anything(),
      expect.objectContaining({
        head: expect.arrayContaining([
          expect.arrayContaining([
            expect.objectContaining({ content: expect.stringContaining('USD') }),
          ]),
        ]),
      })
    )
  })

  it('con warnings en el resultado: no lanza error', async () => {
    const { exportToPdf } = await import('@/lib/export/pdf-export')
    const simWithWarnings = {
      ...mockSimulation,
      result: { ...mockSimulation.result, warnings: ['Loop detectado en task1'] },
    }
    await expect(exportToPdf({
      process: mockProcess, simulation: simWithWarnings, resources: [], heatmapImageData: null,
    })).resolves.not.toThrow()
  })
})
