// Service para Integração com Diários Oficiais (DataJud CNJ)

import { calcularPrazo } from './publicacoes-service'

// API Key pública do DataJud (CNJ)
const DATAJUD_API_KEY = 'cDZHYzlZa0JadVREZDJCendQbXY6SkJlTzNjLV9TRENyQk1RdnFKZGRQdw=='
const DATAJUD_BASE_URL = 'https://api-publica.datajud.cnj.jus.br'

// Mapeamento de tribunais para endpoints da API
const TRIBUNAL_ENDPOINTS: Record<string, string> = {
  TJSP: 'api_publica_tjsp',
  TJRJ: 'api_publica_tjrj',
  TJMG: 'api_publica_tjmg',
  TJRS: 'api_publica_tjrs',
  TJPR: 'api_publica_tjpr',
  TJSC: 'api_publica_tjsc',
  TJBA: 'api_publica_tjba',
  TJPE: 'api_publica_tjpe',
  TJCE: 'api_publica_tjce',
  TJDF: 'api_publica_tjdftj',
  TJGO: 'api_publica_tjgo',
  TJMA: 'api_publica_tjma',
  TJPA: 'api_publica_tjpa',
  TJMT: 'api_publica_tjmt',
  TJMS: 'api_publica_tjms',
  TJES: 'api_publica_tjes',
  TJAL: 'api_publica_tjal',
  TJAM: 'api_publica_tjam',
  TJPB: 'api_publica_tjpb',
  TJPI: 'api_publica_tjpi',
  TJRN: 'api_publica_tjrn',
  TJSE: 'api_publica_tjse',
  TJTO: 'api_publica_tjto',
  TJAC: 'api_publica_tjac',
  TJAP: 'api_publica_tjap',
  TJRO: 'api_publica_tjro',
  TJRR: 'api_publica_tjrr',
  TRF1: 'api_publica_trf1',
  TRF2: 'api_publica_trf2',
  TRF3: 'api_publica_trf3',
  TRF4: 'api_publica_trf4',
  TRF5: 'api_publica_trf5',
  TRF6: 'api_publica_trf6',
  STJ: 'api_publica_stj',
  STF: 'api_publica_stf',
  TST: 'api_publica_tst',
}

// Códigos de movimentos relevantes (tabela unificada CNJ)
const CODIGOS_PUBLICACAO = [92] // Publicação
const CODIGOS_INTIMACAO = [12265, 12021, 12022] // Intimação, Intimação eletrônica, etc
const CODIGOS_CITACAO = [14, 12037] // Citação
const CODIGOS_SENTENCA = [22, 848, 385] // Sentença, Sentença estrangeira homologada
const CODIGOS_ACORDAO = [217, 219] // Acórdão
const CODIGOS_DESPACHO = [11010, 11383] // Despacho, Ato ordinatório

// Keywords para detectar tipo de publicação pelo texto
const KEYWORDS_TIPO: Record<string, RegExp> = {
  INTIMACAO: /\b(intima[çc][aã]o|fica\s+intimad[oa]|intim[ea][\-\s]se)\b/i,
  CITACAO: /\b(cita[çc][aã]o|fica\s+citad[oa]|cit[ea][\-\s]se)\b/i,
  SENTENCA: /\b(senten[çc]a|julgo\s+procedente|julgo\s+improcedente|julgo\s+(parcialmente\s+)?procedente)\b/i,
  ACORDAO: /\b(ac[oó]rd[aã]o|acordam\s+os\s+desembargadores|acordam\s+os\s+ministros)\b/i,
  DESPACHO: /\b(despacho|determino|defiro|indefiro|mero\s+expediente|ato\s+ordinat[oó]rio)\b/i,
}

export interface PublicacaoEncontrada {
  dataPublicacao: Date
  diario: string
  conteudo: string
  tipo: 'INTIMACAO' | 'CITACAO' | 'SENTENCA' | 'DESPACHO' | 'ACORDAO' | 'OUTROS'
  prazoCalculado: Date
  prazoTipo: string
  fonte: 'DATAJUD' | 'DJE_TJSP' | 'ESAJ'
  codigoMovimento?: number
}

export interface ProcessoBuscado {
  id: string
  numeroProcesso: string
  tribunal: string
}

export interface ResultadoBusca {
  sucesso: boolean
  publicacoes: PublicacaoEncontrada[]
  erro?: string
  fonte: string
}

// ===== TIPOS PARA PROCESSO COMPLETO =====

export interface MovimentoCompleto {
  codigo: number
  nome: string
  dataHora: Date
  complementosTabelados?: Array<{ codigo: number; nome: string }>
}

export interface ProcessoCompleto {
  numeroProcesso: string
  classe?: { codigo: number; nome: string }
  sistema?: { codigo: number; nome: string }
  formato?: { codigo: number; nome: string }
  tribunal: string
  dataAjuizamento?: Date
  grau?: string
  nivelSigilo?: number
  orgaoJulgador?: { codigo: number; nome: string }
  assuntos?: Array<{ codigo: number; nome: string }>
  movimentos?: MovimentoCompleto[]
  dadosBrutos?: any
}

export interface ResultadoProcessoCompleto {
  sucesso: boolean
  dados?: ProcessoCompleto
  erro?: string
}

// Remove formatação do número do processo (só dígitos)
function limparNumeroProcesso(numero: string): string {
  return numero.replace(/\D/g, '')
}

// Detecta tipo de publicação baseado no código ou keywords
function detectarTipo(codigoMovimento: number, nomeMovimento: string): PublicacaoEncontrada['tipo'] {
  // Primeiro, verificar pelo código
  if (CODIGOS_INTIMACAO.includes(codigoMovimento)) return 'INTIMACAO'
  if (CODIGOS_CITACAO.includes(codigoMovimento)) return 'CITACAO'
  if (CODIGOS_SENTENCA.includes(codigoMovimento)) return 'SENTENCA'
  if (CODIGOS_ACORDAO.includes(codigoMovimento)) return 'ACORDAO'
  if (CODIGOS_DESPACHO.includes(codigoMovimento)) return 'DESPACHO'
  
  // Se for publicação genérica, tentar detectar pelo nome
  if (CODIGOS_PUBLICACAO.includes(codigoMovimento)) {
    for (const [tipo, regex] of Object.entries(KEYWORDS_TIPO)) {
      if (regex.test(nomeMovimento)) {
        return tipo as PublicacaoEncontrada['tipo']
      }
    }
  }
  
  return 'OUTROS'
}

// ===== BUSCA PROCESSO COMPLETO NA API DATAJUD =====
export async function buscarProcessoCompleto(
  numeroProcesso: string,
  tribunal: string
): Promise<ResultadoProcessoCompleto> {
  const endpoint = TRIBUNAL_ENDPOINTS[tribunal.toUpperCase()]
  
  if (!endpoint) {
    return {
      sucesso: false,
      erro: `Tribunal ${tribunal} não suportado na API DataJud`,
    }
  }
  
  const numeroLimpo = limparNumeroProcesso(numeroProcesso)
  const url = `${DATAJUD_BASE_URL}/${endpoint}/_search`
  
  try {
    const response = await fetch(url, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `APIKey ${DATAJUD_API_KEY}`,
      },
      body: JSON.stringify({
        size: 1,
        query: {
          match: {
            numeroProcesso: numeroLimpo,
          },
        },
      }),
    })
    
    if (!response.ok) {
      const errorText = await response.text()
      console.error(`[DataJud] Erro HTTP ${response.status}:`, errorText)
      return {
        sucesso: false,
        erro: `HTTP ${response.status}: ${errorText.substring(0, 200)}`,
      }
    }
    
    const data = await response.json()
    const hits = data.hits?.hits || []
    
    if (hits.length === 0) {
      return {
        sucesso: true,
        dados: undefined,
        erro: 'Processo não encontrado na API DataJud',
      }
    }
    
    const processo = hits[0]._source
    
    // Mapear movimentos com todos os dados
    const movimentos: MovimentoCompleto[] = (processo.movimentos || []).map((m: any) => ({
      codigo: m.codigo,
      nome: m.nome || 'Movimentação sem nome',
      dataHora: new Date(m.dataHora),
      complementosTabelados: m.complementosTabelados || [],
    }))
    
    // Ordenar movimentos por data (mais recente primeiro)
    movimentos.sort((a, b) => b.dataHora.getTime() - a.dataHora.getTime())
    
    const dadosCompletos: ProcessoCompleto = {
      numeroProcesso: processo.numeroProcesso,
      classe: processo.classe,
      sistema: processo.sistema,
      formato: processo.formato,
      tribunal: tribunal,
      dataAjuizamento: processo.dataAjuizamento ? new Date(processo.dataAjuizamento) : undefined,
      grau: processo.grau,
      nivelSigilo: processo.nivelSigilo,
      orgaoJulgador: processo.orgaoJulgador,
      assuntos: processo.assuntos || [],
      movimentos,
      dadosBrutos: processo,
    }
    
    console.log(`[DataJud] Processo ${numeroProcesso}: ${movimentos.length} movimentos encontrados`)
    
    return {
      sucesso: true,
      dados: dadosCompletos,
    }
  } catch (error) {
    console.error(`[DataJud] Erro ao buscar ${numeroProcesso}:`, error)
    return {
      sucesso: false,
      erro: error instanceof Error ? error.message : 'Erro desconhecido',
    }
  }
}

// Busca processo na API DataJud (versão que filtra publicações)
export async function buscarDataJud(
  numeroProcesso: string,
  tribunal: string
): Promise<ResultadoBusca> {
  const endpoint = TRIBUNAL_ENDPOINTS[tribunal.toUpperCase()]
  
  if (!endpoint) {
    return {
      sucesso: false,
      publicacoes: [],
      erro: `Tribunal ${tribunal} não suportado na API DataJud`,
      fonte: 'DATAJUD',
    }
  }
  
  const numeroLimpo = limparNumeroProcesso(numeroProcesso)
  const url = `${DATAJUD_BASE_URL}/${endpoint}/_search`
  
  try {
    const response = await fetch(url, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `APIKey ${DATAJUD_API_KEY}`,
      },
      body: JSON.stringify({
        size: 1,
        query: {
          match: {
            numeroProcesso: numeroLimpo,
          },
        },
      }),
    })
    
    if (!response.ok) {
      const errorText = await response.text()
      console.error(`[DataJud] Erro HTTP ${response.status}:`, errorText)
      return {
        sucesso: false,
        publicacoes: [],
        erro: `HTTP ${response.status}: ${errorText.substring(0, 200)}`,
        fonte: 'DATAJUD',
      }
    }
    
    const data = await response.json()
    const hits = data.hits?.hits || []
    
    if (hits.length === 0) {
      return {
        sucesso: true,
        publicacoes: [],
        fonte: 'DATAJUD',
      }
    }
    
    const processo = hits[0]._source
    const movimentos = processo.movimentos || []
    
    // Filtrar movimentos relevantes (Publicação, Intimação, Citação, Sentença, Despacho)
    const codigosRelevantes = [
      ...CODIGOS_PUBLICACAO,
      ...CODIGOS_INTIMACAO,
      ...CODIGOS_CITACAO,
      ...CODIGOS_SENTENCA,
      ...CODIGOS_ACORDAO,
      ...CODIGOS_DESPACHO,
    ]
    
    const movimentosRelevantes = movimentos.filter((m: any) => 
      codigosRelevantes.includes(m.codigo) ||
      m.nome?.toLowerCase().includes('publicação') ||
      m.nome?.toLowerCase().includes('intimação') ||
      m.nome?.toLowerCase().includes('citação') ||
      m.nome?.toLowerCase().includes('sentença')
    )
    
    const publicacoes: PublicacaoEncontrada[] = movimentosRelevantes.map((mov: any) => {
      const dataPublicacao = new Date(mov.dataHora)
      const tipo = detectarTipo(mov.codigo, mov.nome || '')
      const { prazoCalculado, prazoTipo } = calcularPrazo(dataPublicacao, tipo)
      
      // Construir conteúdo descritivo
      const complementos = mov.complementosTabelados?.map((c: any) => c.nome).join(', ') || ''
      const orgao = mov.orgaoJulgador?.nome || ''
      
      const conteudo = [
        `${mov.nome || 'Movimentação'}`,
        processo.classe?.nome ? `Classe: ${processo.classe.nome}` : '',
        complementos ? `Complemento: ${complementos}` : '',
        orgao ? `Órgão: ${orgao}` : '',
        `Processo: ${numeroProcesso}`,
        `Tribunal: ${tribunal}`,
      ].filter(Boolean).join('. ')
      
      return {
        dataPublicacao,
        diario: 'DJe',
        conteudo,
        tipo,
        prazoCalculado,
        prazoTipo,
        fonte: 'DATAJUD' as const,
        codigoMovimento: mov.codigo,
      }
    })
    
    // Ordenar por data decrescente
    publicacoes.sort((a, b) => b.dataPublicacao.getTime() - a.dataPublicacao.getTime())
    
    console.log(`[DataJud] Processo ${numeroProcesso}: ${publicacoes.length} publicações encontradas`)
    
    return {
      sucesso: true,
      publicacoes,
      fonte: 'DATAJUD',
    }
  } catch (error) {
    console.error(`[DataJud] Erro ao buscar ${numeroProcesso}:`, error)
    return {
      sucesso: false,
      publicacoes: [],
      erro: error instanceof Error ? error.message : 'Erro desconhecido',
      fonte: 'DATAJUD',
    }
  }
}

// Busca no DJe TJSP via scraping (backup)
export async function buscarDJeTJSP(numeroProcesso: string): Promise<ResultadoBusca> {
  // TODO: Implementar scraping do DJe TJSP como backup
  // Por enquanto, retorna vazio - pode ser implementado com puppeteer/cheerio
  console.log(`[DJe TJSP] Scraping não implementado para ${numeroProcesso}`)
  return {
    sucesso: true,
    publicacoes: [],
    fonte: 'DJE_TJSP',
  }
}

// Função principal que tenta todas as fontes
export async function buscarPublicacoesReais(
  processo: ProcessoBuscado,
  diasAtras: number = 30
): Promise<ResultadoBusca> {
  console.log(`[Diarios] Buscando publicações para ${processo.numeroProcesso} (${processo.tribunal})`)
  
  // 1. Tentar DataJud primeiro (fonte principal)
  const resultadoDataJud = await buscarDataJud(processo.numeroProcesso, processo.tribunal)
  
  if (resultadoDataJud.sucesso && resultadoDataJud.publicacoes.length > 0) {
    // Filtrar apenas publicações dos últimos N dias
    const dataLimite = new Date()
    dataLimite.setDate(dataLimite.getDate() - diasAtras)
    
    const publicacoesRecentes = resultadoDataJud.publicacoes.filter(
      pub => pub.dataPublicacao >= dataLimite
    )
    
    return {
      ...resultadoDataJud,
      publicacoes: publicacoesRecentes,
    }
  }
  
  // 2. Se DataJud falhou ou não encontrou, tentar DJe TJSP (se for TJSP)
  if (processo.tribunal.toUpperCase() === 'TJSP') {
    const resultadoDJe = await buscarDJeTJSP(processo.numeroProcesso)
    if (resultadoDJe.sucesso && resultadoDJe.publicacoes.length > 0) {
      return resultadoDJe
    }
  }
  
  // 3. Retornar resultado (mesmo vazio)
  return resultadoDataJud
}

// Busca em lote com rate limiting
export async function buscarPublicacoesEmLote(
  processos: ProcessoBuscado[],
  delayMs: number = 500
): Promise<Map<string, ResultadoBusca>> {
  const resultados = new Map<string, ResultadoBusca>()
  
  for (let i = 0; i < processos.length; i++) {
    const processo = processos[i]
    console.log(`[Diarios] Processando ${i + 1}/${processos.length}: ${processo.numeroProcesso}`)
    
    try {
      const resultado = await buscarPublicacoesReais(processo)
      resultados.set(processo.id, resultado)
    } catch (error) {
      console.error(`[Diarios] Erro no processo ${processo.numeroProcesso}:`, error)
      resultados.set(processo.id, {
        sucesso: false,
        publicacoes: [],
        erro: error instanceof Error ? error.message : 'Erro desconhecido',
        fonte: 'DATAJUD',
      })
    }
    
    // Rate limiting entre requisições
    if (i < processos.length - 1) {
      await new Promise(resolve => setTimeout(resolve, delayMs))
    }
  }
  
  return resultados
}
