import jsPDF from 'jspdf'
import html2canvas from 'html2canvas'
import { PDFDocument } from 'pdf-lib'

interface DesignConfig {
  capa?: {
    corPrimaria: string
    corSecundaria: string
    titulo: string
    subtitulo: string
    cliente: string
    numeroDocumento: string
    contrato: string
    fornecedor: string
    logoCliente?: string
    logoFornecedor?: string
  }
  indice?: {
    corTitulo: string
    corLinha: string
    bilingue: boolean
    titulo: string
  }
  divisora?: {
    estilo: 'minimalista' | 'lateral' | 'corporativa'
    corPrimaria: string
    corSecundaria: string
    bilingue: boolean
    icone: string
  }
  cabecalho?: {
    corBorda: string
    altura: number
    estilo: 'simples' | 'completo' | 'minimalista'
  }
  rodape?: {
    corBorda: string
    altura: number
    estilo: 'simples' | 'completo' | 'minimalista'
    mostrarPagina: boolean
  }
  marcaAgua?: string
}

interface Topico {
  id: string
  numero_topico: string
  titulo: string
  descricao?: string
  obrigatorio: boolean
}

interface Documento {
  id: string
  titulo: string
  arquivo_url: string
  arquivo_tipo: string
}

interface PDFGeneratorOptions {
  projeto: any
  topicos: Topico[]
  documentosPorSecao: { [key: string]: Documento[] }
  designConfig?: DesignConfig
  onProgress?: (progress: number, message: string) => void
}

export class PDFGenerator {
  private pdf: jsPDF
  private pageNumber: number = 0
  private config: DesignConfig
  private projeto: any
  
  constructor(options: PDFGeneratorOptions) {
    this.pdf = new jsPDF('p', 'mm', 'a4')
    this.projeto = options.projeto
    this.config = options.designConfig || this.getDefaultConfig()
  }
  
  private getDefaultConfig(): DesignConfig {
    return {
      capa: {
        corPrimaria: '#1a365d',
        corSecundaria: '#2b6cb0',
        titulo: 'DATABOOK',
        subtitulo: '',
        cliente: '',
        numeroDocumento: '',
        contrato: '',
        fornecedor: ''
      },
      indice: {
        corTitulo: '#1a365d',
        corLinha: '#2b6cb0',
        bilingue: false,
        titulo: 'ÍNDICE'
      },
      divisora: {
        estilo: 'minimalista',
        corPrimaria: '#1a365d',
        corSecundaria: '#2b6cb0',
        bilingue: false,
        icone: ''
      },
      cabecalho: {
        corBorda: '#2b6cb0',
        altura: 15,
        estilo: 'simples'
      },
      rodape: {
        corBorda: '#cbd5e0',
        altura: 10,
        estilo: 'simples',
        mostrarPagina: true
      }
    }
  }
  
  async generate(options: PDFGeneratorOptions): Promise<Blob> {
    const { topicos, documentosPorSecao, onProgress } = options
    
    try {
      // 1. Gerar Capa
      onProgress?.(10, 'Gerando capa...')
      await this.generateCapa()
      
      // 2. Gerar Índice
      onProgress?.(20, 'Gerando índice...')
      await this.generateIndice(topicos)
      
      // 3. Gerar Seções
      let progress = 20
      const progressPerSection = 70 / topicos.length
      
      for (const topico of topicos) {
        const docs = documentosPorSecao[topico.numero_topico] || []
        
        onProgress?.(progress, `Gerando seção ${topico.numero_topico}...`)
        
        // Divisora da seção
        await this.generateDivisora(topico)
        
        // Documentos da seção
        if (docs.length > 0) {
          for (const doc of docs) {
            await this.generateDocumentPage(doc, topico)
          }
        } else {
          await this.generateNaoAplicavelPage(topico)
        }
        
        progress += progressPerSection
      }
      
      onProgress?.(95, 'Mesclando documentos originais...')
      
      // Usa pdf-lib para mesclar tudo
      const finalPdfBytes = await this.mergeDocuments(topicos, documentosPorSecao)
      
      const blob = new Blob([finalPdfBytes as unknown as ArrayBuffer], { type: 'application/pdf' })
      onProgress?.(100, 'PDF gerado com sucesso!')
      
      return blob
    } catch (error) {
      console.error('Erro ao gerar PDF:', error)
      throw error
    }
  }
  
  private async generateCapa(): Promise<void> {
    const capa = this.config.capa!
    
    // Criar elemento HTML para a capa
    const capaElement = document.createElement('div')
    capaElement.style.width = '210mm'
    capaElement.style.height = '297mm'
    capaElement.style.background = `linear-gradient(135deg, ${capa.corPrimaria} 0%, ${capa.corSecundaria} 100%)`
    capaElement.style.color = 'white'
    capaElement.style.padding = '40mm'
    capaElement.style.display = 'flex'
    capaElement.style.flexDirection = 'column'
    capaElement.style.justifyContent = 'space-between'
    capaElement.style.fontFamily = 'Arial, sans-serif'
    capaElement.style.position = 'absolute'
    capaElement.style.left = '-9999px'
    
    capaElement.innerHTML = `
      <div>
        ${capa.logoCliente ? `<img src="${capa.logoCliente}" style="max-width: 200px; max-height: 100px; margin-bottom: 30px;" />` : ''}
      </div>
      <div style="text-align: center;">
        <h1 style="font-size: 48px; font-weight: bold; margin: 0 0 20px 0;">${capa.titulo}</h1>
        ${capa.subtitulo ? `<h2 style="font-size: 32px; font-weight: normal; margin: 0 0 40px 0;">${capa.subtitulo}</h2>` : ''}
        <div style="width: 60%; height: 3px; background: rgba(255,255,255,0.5); margin: 40px auto;"></div>
        <div style="margin-top: 40px;">
          <p style="font-size: 24px; font-weight: 600; margin: 10px 0;">${capa.numeroDocumento}</p>
          <p style="font-size: 20px; margin: 10px 0;">Contrato: ${capa.contrato}</p>
          <p style="font-size: 20px; margin: 10px 0;">Cliente: ${capa.cliente}</p>
          <p style="font-size: 18px; margin: 10px 0;">${new Date().getFullYear()}</p>
        </div>
      </div>
      <div style="text-align: center;">
        ${capa.logoFornecedor ? `<img src="${capa.logoFornecedor}" style="max-width: 150px; max-height: 75px;" />` : `<p style="font-size: 20px;">${capa.fornecedor}</p>`}
      </div>
    `
    
    document.body.appendChild(capaElement)
    
    const canvas = await html2canvas(capaElement, { scale: 2 })
    const imgData = canvas.toDataURL('image/png')
    
    this.pdf.addImage(imgData, 'PNG', 0, 0, 210, 297)
    this.pageNumber++
    
    document.body.removeChild(capaElement)
  }
  
  private async generateIndice(topicos: Topico[]): Promise<void> {
    this.pdf.addPage()
    this.pageNumber++
    
    const indice = this.config.indice!
    
    // Título
    this.pdf.setFontSize(24)
    this.pdf.setTextColor(indice.corTitulo)
    this.pdf.setFont('helvetica', 'bold')
    this.pdf.text(indice.titulo, 105, 30, { align: 'center' })
    
    // Linha divisória
    this.pdf.setDrawColor(indice.corLinha)
    this.pdf.setLineWidth(0.5)
    this.pdf.line(20, 40, 190, 40)
    
    // Itens do índice
    let y = 55
    this.pdf.setFontSize(12)
    
    topicos.forEach((topico, index) => {
      if (y > 270) {
        this.pdf.addPage()
        this.pageNumber++
        y = 30
      }
      
      const indent = (topico.numero_topico.split('.').length - 1) * 5
      
      this.pdf.setFont('helvetica', 'bold')
      this.pdf.setTextColor('#2b6cb0')
      this.pdf.text(topico.numero_topico, 20 + indent, y)
      
      this.pdf.setFont('helvetica', 'normal')
      this.pdf.setTextColor('#000000')
      this.pdf.text(topico.titulo, 40 + indent, y, { maxWidth: 130 })
      
      // Número da página (simulado)
      this.pdf.text((index + 3).toString(), 185, y, { align: 'right' })
      
      y += 8
    })
  }
  
  private async generateDivisora(topico: Topico): Promise<void> {
    this.pdf.addPage()
    this.pageNumber++
    
    const divisora = this.config.divisora!
    
    if (divisora.estilo === 'minimalista') {
      await this.generateDivisoraMinimalista(topico)
    } else if (divisora.estilo === 'lateral') {
      await this.generateDivisoraLateral(topico)
    } else {
      await this.generateDivisoraCorporativa(topico)
    }
  }
  
  private async generateDivisoraMinimalista(topico: Topico): Promise<void> {
    const divisora = this.config.divisora!
    
    // Watermark do número
    this.pdf.setFontSize(150)
    this.pdf.setTextColor(divisora.corPrimaria)
    this.pdf.setGState(this.pdf.GState({ opacity: 0.08 }))
    this.pdf.text(topico.numero_topico, 105, 160, { align: 'center' })
    this.pdf.setGState(this.pdf.GState({ opacity: 1 }))
    
    // Conteúdo
    this.pdf.setFontSize(36)
    this.pdf.setTextColor(divisora.corSecundaria)
    this.pdf.setFont('helvetica', 'bold')
    this.pdf.text(`Seção ${topico.numero_topico}`, 105, 120, { align: 'center' })
    
    this.pdf.setFontSize(32)
    this.pdf.setTextColor(divisora.corPrimaria)
    this.pdf.text(topico.titulo, 105, 140, { align: 'center', maxWidth: 160 })
    
    if (topico.descricao) {
      this.pdf.setFontSize(16)
      this.pdf.setTextColor('#718096')
      this.pdf.setFont('helvetica', 'italic')
      this.pdf.text(topico.descricao, 105, 160, { align: 'center', maxWidth: 140 })
    }
    
    // Linha decorativa
    this.pdf.setDrawColor(divisora.corSecundaria)
    this.pdf.setLineWidth(0.5)
    this.pdf.line(80, 175, 130, 175)
  }
  
  private async generateDivisoraLateral(topico: Topico): Promise<void> {
    const divisora = this.config.divisora!
    
    // Barra lateral
    this.pdf.setFillColor(divisora.corPrimaria)
    this.pdf.rect(0, 0, 20, 297, 'F')
    
    // Número na barra
    this.pdf.setFontSize(48)
    this.pdf.setTextColor('#ffffff')
    this.pdf.setFont('helvetica', 'bold')
    this.pdf.text(topico.numero_topico, 10, 150, { align: 'center', angle: 0 })
    
    // Conteúdo principal
    this.pdf.setFontSize(28)
    this.pdf.setTextColor(divisora.corPrimaria)
    this.pdf.text(topico.titulo, 35, 140, { maxWidth: 160 })
    
    if (topico.descricao) {
      this.pdf.setFontSize(14)
      this.pdf.setTextColor('#718096')
      this.pdf.setFont('helvetica', 'italic')
      this.pdf.text(topico.descricao, 35, 160, { maxWidth: 160 })
    }
    
    // Informações do projeto no rodapé
    this.pdf.setFontSize(10)
    this.pdf.setTextColor('#718096')
    this.pdf.setFont('helvetica', 'normal')
    this.pdf.text(`Projeto: ${this.projeto?.nome_projeto || ''}`, 35, 270)
    this.pdf.text(`Documento: ${this.config.capa?.numeroDocumento || ''}`, 35, 277)
  }
  
  private async generateDivisoraCorporativa(topico: Topico): Promise<void> {
    const divisora = this.config.divisora!
    
    // Header colorido
    this.pdf.setFillColor(divisora.corPrimaria)
    this.pdf.rect(0, 0, 210, 80, 'F')
    
    // Conteúdo
    this.pdf.setFontSize(48)
    this.pdf.setTextColor(divisora.corPrimaria)
    this.pdf.setFont('helvetica', 'bold')
    this.pdf.text(topico.numero_topico, 105, 120, { align: 'center' })
    
    this.pdf.setFontSize(28)
    this.pdf.text(topico.titulo, 105, 145, { align: 'center', maxWidth: 160 })
    
    // Caixa de informações
    this.pdf.setDrawColor('#e2e8f0')
    this.pdf.setLineWidth(0.5)
    this.pdf.roundedRect(40, 170, 130, 60, 3, 3, 'S')
    
    this.pdf.setFontSize(10)
    this.pdf.setTextColor('#718096')
    this.pdf.setFont('helvetica', 'bold')
    let infoY = 180
    
    const infos = [
      ['Projeto:', this.projeto?.nome_projeto?.substring(0, 40) || ''],
      ['Cliente:', this.config.capa?.cliente || ''],
      ['Contrato:', this.config.capa?.contrato || ''],
      ['Documento:', this.config.capa?.numeroDocumento || '']
    ]
    
    infos.forEach(([label, value]) => {
      this.pdf.text(label, 45, infoY)
      this.pdf.setFont('helvetica', 'normal')
      this.pdf.setTextColor('#2d3748')
      this.pdf.text(value, 75, infoY)
      this.pdf.setFont('helvetica', 'bold')
      this.pdf.setTextColor('#718096')
      infoY += 12
    })
  }
  
  private async generateDocumentPage(doc: Documento, topico: Topico): Promise<void> {
    // Se for imagem ou PDF, será processado depois com pdf-lib
    // Aqui apenas marcamos para processamento posterior
    if (doc.arquivo_url.startsWith('data:image') || doc.arquivo_url.startsWith('data:application/pdf')) {
      // Será processado na função mergeDocuments
      return
    }
    
    // Para outros tipos de documento
    this.pdf.addPage()
    this.pageNumber++
    
    // Cabeçalho
    await this.addHeader()
    
    // Título do documento
    this.pdf.setFontSize(14)
    this.pdf.setTextColor('#000000')
    this.pdf.setFont('helvetica', 'bold')
    this.pdf.text(doc.titulo, 20, 35)
    
    this.pdf.setFontSize(10)
    this.pdf.setTextColor('#718096')
    this.pdf.setFont('helvetica', 'normal')
    this.pdf.text(`Seção ${topico.numero_topico}`, 20, 42)
    
    // Linha divisória
    this.pdf.setDrawColor('#e2e8f0')
    this.pdf.line(20, 45, 190, 45)
    
    this.pdf.setFontSize(12)
    this.pdf.setTextColor('#718096')
    this.pdf.text(`Documento: ${doc.titulo}`, 105, 150, { align: 'center' })
    this.pdf.text(`Tipo: ${doc.arquivo_tipo}`, 105, 160, { align: 'center' })
    
    // Rodapé
    await this.addFooter()
  }
  
  private async mergeDocuments(topicos: Topico[], documentosPorSecao: { [key: string]: Documento[] }): Promise<Uint8Array> {
    const mergedPdf = await PDFDocument.create()
    
    // Primeiro, adiciona capa e índice do jsPDF
    const jsPdfBytes = this.pdf.output('arraybuffer')
    const jsPdfDoc = await PDFDocument.load(jsPdfBytes)
    
    // Copia apenas as primeiras páginas (capa e índice)
    let currentJsPdfPage = 0
    const totalJsPdfPages = jsPdfDoc.getPageCount()
    
    // Adiciona capa e índice (primeiras 2 páginas)
    if (totalJsPdfPages >= 2) {
      const initialPages = await mergedPdf.copyPages(jsPdfDoc, [0, 1])
      initialPages.forEach(page => mergedPdf.addPage(page))
      currentJsPdfPage = 2
    }
    
    // Agora processa cada seção
    for (const topico of topicos) {
      const docs = documentosPorSecao[topico.numero_topico] || []
      
      // Adiciona página divisora da seção (do jsPDF)
      if (currentJsPdfPage < totalJsPdfPages) {
        const [divisoraPage] = await mergedPdf.copyPages(jsPdfDoc, [currentJsPdfPage])
        mergedPdf.addPage(divisoraPage)
        currentJsPdfPage++
      }
      
      // Adiciona os documentos originais
      if (docs.length > 0) {
        for (const doc of docs) {
          try {
            console.log(`Processando documento: ${doc.titulo}, tipo: ${doc.arquivo_tipo}, URL: ${doc.arquivo_url.substring(0, 50)}...`)
            
            // Busca o arquivo original
            let fileBytes: ArrayBuffer
            
            if (doc.arquivo_url.startsWith('data:')) {
              // Converte data URL para bytes
              const base64Data = doc.arquivo_url.split(',')[1]
              const binaryString = atob(base64Data)
              const bytes = new Uint8Array(binaryString.length)
              for (let i = 0; i < binaryString.length; i++) {
                bytes[i] = binaryString.charCodeAt(i)
              }
              fileBytes = bytes.buffer
            } else {
              // Busca do Supabase Storage
              const response = await fetch(doc.arquivo_url)
              fileBytes = await response.arrayBuffer()
            }
            
            console.log(`Arquivo carregado, tamanho: ${fileBytes.byteLength} bytes`)
            
            if (doc.arquivo_tipo.includes('pdf') || doc.arquivo_url.includes('application/pdf')) {
              // É um PDF - faz merge das páginas
              console.log('Processando como PDF...')
              const pdfDoc = await PDFDocument.load(fileBytes)
              const numPages = pdfDoc.getPageCount()
              console.log(`PDF tem ${numPages} páginas`)
              
              const pdfPages = await mergedPdf.copyPages(pdfDoc, pdfDoc.getPageIndices())
              pdfPages.forEach(page => {
                mergedPdf.addPage(page)
              })
              console.log(`${numPages} páginas adicionadas ao PDF final`)
            } else if (doc.arquivo_tipo.includes('image') || doc.arquivo_url.startsWith('data:image')) {
              // É uma imagem - adiciona em página A4
              console.log('Processando como imagem...')
              let image
              if (doc.arquivo_tipo.includes('png') || doc.arquivo_url.includes('png')) {
                image = await mergedPdf.embedPng(new Uint8Array(fileBytes))
              } else {
                image = await mergedPdf.embedJpg(new Uint8Array(fileBytes))
              }
              
              const page = mergedPdf.addPage([595.28, 841.89]) // A4 em pontos
              const { width, height } = image.scale(1)
              
              // Calcula escala para caber na página mantendo proporção
              const scale = Math.min(595.28 / width, 841.89 / height)
              const scaledWidth = width * scale
              const scaledHeight = height * scale
              
              // Centraliza a imagem
              const x = (595.28 - scaledWidth) / 2
              const y = (841.89 - scaledHeight) / 2
              
              page.drawImage(image, {
                x,
                y,
                width: scaledWidth,
                height: scaledHeight
              })
              console.log('Imagem adicionada ao PDF final')
            }
          } catch (error) {
            console.error(`Erro ao adicionar documento ${doc.titulo}:`, error)
          }
        }
      } else {
        // Adiciona página "Não Aplicável" (do jsPDF)
        if (currentJsPdfPage < totalJsPdfPages) {
          const [naoAplicavelPage] = await mergedPdf.copyPages(jsPdfDoc, [currentJsPdfPage])
          mergedPdf.addPage(naoAplicavelPage)
          currentJsPdfPage++
        }
      }
    }
    
    console.log(`PDF final tem ${mergedPdf.getPageCount()} páginas`)
    return await mergedPdf.save()
  }
  
  private async generateNaoAplicavelPage(_topico: Topico): Promise<void> {
    this.pdf.addPage()
    this.pageNumber++
    
    // Cabeçalho
    await this.addHeader()
    
    // Conteúdo "Não Aplicável"
    this.pdf.setFontSize(24)
    this.pdf.setTextColor('#cbd5e0')
    this.pdf.setFont('helvetica', 'bold')
    this.pdf.text('Não Aplicável', 105, 145, { align: 'center' })
    
    this.pdf.setFontSize(12)
    this.pdf.setTextColor('#718096')
    this.pdf.setFont('helvetica', 'normal')
    this.pdf.text('Nenhum documento disponível para esta seção', 105, 170, { align: 'center' })
    
    // Rodapé
    await this.addFooter()
  }
  
  private async addHeader(): Promise<void> {
    const header = this.config.cabecalho!
    
    if (header.estilo === 'simples') {
      this.pdf.setDrawColor(header.corBorda)
      this.pdf.setLineWidth(0.5)
      this.pdf.line(20, 20, 190, 20)
      
      this.pdf.setFontSize(10)
      this.pdf.setTextColor('#2d3748')
      this.pdf.text(this.projeto?.nome_projeto?.substring(0, 50) || '', 20, 17)
      this.pdf.text(this.config.capa?.numeroDocumento || '', 190, 17, { align: 'right' })
    }
  }
  
  private async addFooter(): Promise<void> {
    const footer = this.config.rodape!
    
    this.pdf.setDrawColor(footer.corBorda)
    this.pdf.setLineWidth(0.3)
    this.pdf.line(20, 280, 190, 280)
    
    this.pdf.setFontSize(9)
    this.pdf.setTextColor('#718096')
    
    this.pdf.text(`Rev. 01 | ${new Date().getFullYear()}`, 20, 287)
    
    if (footer.mostrarPagina) {
      this.pdf.setFontSize(14)
      this.pdf.setTextColor(this.config.capa?.corPrimaria || '#1a365d')
      this.pdf.setFont('helvetica', 'bold')
      this.pdf.text(this.pageNumber.toString(), 105, 287, { align: 'center' })
    }
    
    this.pdf.setFontSize(9)
    this.pdf.setTextColor('#718096')
    this.pdf.setFont('helvetica', 'normal')
    this.pdf.text(this.config.capa?.fornecedor || '', 190, 287, { align: 'right' })
  }
}

// Função helper para gerar PDF
export async function generateDatabookPDF(options: PDFGeneratorOptions): Promise<Blob> {
  const generator = new PDFGenerator(options)
  return await generator.generate(options)
}
