import api from './api';
import { conciliacaoService } from './conciliacaoService';
import { workspaceConciliacaoService } from './workspaceConciliacaoService';

/**
 * Normaliza texto para comparação (remove acentos, converte para minúsculas, remove caracteres especiais)
 * @param {string} str - Texto a ser normalizado
 * @returns {string} - Texto normalizado
 */
export const normalizeText = (str) => {
  if (!str) return "";
  return str
    .toLowerCase()
    .normalize("NFD")
    .replace(/[\u0300-\u036f]/g, "") // Remove acentos
    .replace(/[^a-z0-9\s]/g, "") // Mantém apenas alfanuméricos e espaços
    .trim();
};

/**
 * Converte dados do backend para array (suporta objeto de objetos)
 * @param {any} data - Dados do backend
 * @returns {Array} - Array de dados
 */
const toArray = (data) => {
  if (!data) return [];
  if (Array.isArray(data)) return data;

  // Se tem Base_Dados_API, extrai de lá
  if (data.Base_Dados_API) {
    const baseData = data.Base_Dados_API;
    if (Array.isArray(baseData)) return baseData;
    return Object.values(baseData || {});
  }

  // Se é objeto, converte para array
  return Object.values(data || {});
};

/**
 * Prepara o objeto de atualização padronizado
 * @param {number} idExtrato - ID da transação
 * @param {Object} regra - Dados da regra ou objeto de reset
 * @returns {Object} - Objeto de atualização
 */
const prepararUpdate = (idExtrato, regra) => {
  return {
    idextrato: idExtrato,
    regra: regra.idregras_financeiro || regra.id || "0",
    categoria: regra.categoria || "0",
    beneficiario_pagador: regra.beneficiario_pagador || regra.beneficiario || "0",
    caixinha: regra.caixinha || "0",
    Resutl: true
  };
};

/**
 * Executa as atualizações de uma transação (3 endpoints em paralelo)
 * @param {Object} objeto - Objeto de atualização
 * @returns {Promise<void>}
 */
const executarUpdates = async (objeto) => {
  try {
    console.log('[reconciliationEngine] Executando updates para transação:', objeto.idextrato);

    // Executa os endpoints
    // Nota: O código original usa "UPDATE" como método HTTP customizado
    const results = await Promise.allSettled([
      // 1. Atualiza regra e categoria (POST) - Este é o principal e sempre funciona
      api.post('/regra_categoria/edit', {
        idextrato: objeto.idextrato,
        regra: objeto.regra,
        categoria: objeto.categoria
      }),
      // 2. Atualiza beneficiário/pagador (UPDATE - método HTTP customizado)
      api.request({
        url: '/beneficiario_pagador/inserir',
        method: 'UPDATE',
        data: {
          idextrato: objeto.idextrato,
          beneficiario_pagador: objeto.beneficiario_pagador
        }
      }),
      // 3. Atualiza caixinha (UPDATE - método HTTP customizado)
      api.request({
        url: '/caixinha_extrato/inserir',
        method: 'UPDATE',
        data: {
          idextrato: objeto.idextrato,
          caixinha: objeto.caixinha
        }
      })
    ]);

    // Verifica resultados e loga avisos para endpoints que falharam com 405
    results.forEach((result, index) => {
      const endpointNames = [
        '/regra_categoria/edit',
        '/beneficiario_pagador/inserir',
        '/caixinha_extrato/inserir'
      ];

      if (result.status === 'rejected') {
        const error = result.reason;
        if (error.response?.status === 405) {
          console.warn(`[reconciliationEngine] Endpoint ${endpointNames[index]} retornou 405 (METHOD NOT ALLOWED), ignorando`);
        } else {
          // Re-lança erros que não são 405
          throw error;
        }
      }
    });

    console.log('[reconciliationEngine] Updates concluídos para transação:', objeto.idextrato);
  } catch (error) {
    console.error(`[reconciliationEngine] Erro ao atualizar transação ${objeto.idextrato}:`, error);
    throw error;
  }
};

/**
 * Processa a conciliação bancária automática
 * Implementa Scoring de Afinidade, Indexação e Propagação de Regras
 * 
 * @param {Object} options - Opções de conciliação
 * @param {Function} [options.onProgress] - Callback de progresso (processados, total)
 * @returns {Promise<Object>} - Resultado da conciliação { sucesso, processados, erros }
 */
export const processarReconciliacao = async ({ onProgress } = {}) => {
  console.time("⏱️ Tempo Total de Conciliação");
  console.log('[reconciliationEngine] ========== INICIANDO CONCILIAÇÃO AUTOMÁTICA ==========');

  try {
    // 1. Busca de Dados em Paralelo
    console.log('[reconciliationEngine] Buscando dados em paralelo...');
    const [extratoRes, empresasRes, regrasRes] = await Promise.all([
      conciliacaoService.fetchStatement(),
      api.get('/empresas_financeiro').catch(() => ({ data: { Base_Dados_API: [] } })),
      conciliacaoService.fetchRules()
    ]);

    // Normaliza respostas
    const Extrato = toArray(extratoRes);
    const Empresas = toArray(empresasRes?.data || empresasRes);
    const Regras = toArray(regrasRes);

    console.log('[reconciliationEngine] Dados carregados:', {
      extrato: Extrato.length,
      empresas: Empresas.length,
      regras: Regras.length
    });

    // 2. Criação de Mapas (Indexação) para busca O(1)
    const regrasMap = new Map();
    const regrasLista = [];

    Regras.forEach(r => {
      const regraId = r.idregras_financeiro || r.id;
      if (regraId) {
        regrasMap.set(Number(regraId), r);
      }

      if (r.condicional) {
        regrasLista.push({
          ...r,
          condNorm: normalizeText(r.condicional).trim()
        });
      }
    });

    // Prioriza condicionais mais longas/específicas para evitar que regras curtas "roubem" o match
    regrasLista.sort((a, b) => b.condNorm.length - a.condNorm.length);

    const empresasCpfMap = new Map();
    Empresas.forEach(e => {
      if (e.cpf_cnpj) {
        const cpfLimpo = e.cpf_cnpj.replace(/\D/g, '');
        if (cpfLimpo) {
          empresasCpfMap.set(cpfLimpo, e);
        }
      }
    });

    let updates = [];
    let processadas = 0;
    const total = Extrato.length;

    console.groupCollapsed("📈 Processamento de Transações");

    // 3. Processa cada transação
    for (const transacao of Extrato) {
      const idExtrato = transacao.idextrato || transacao.id;
      if (!idExtrato) {
        console.warn('[reconciliationEngine] Transação sem ID, pulando:', transacao);
        continue;
      }

      const descricaoNorm = normalizeText(transacao.descricao || "");
      const valorTransacao = Number(transacao.valor) || 0;
      const regraAtual = transacao.regra || transacao.regraId;

      // --- LÓGICA 1: PROPAGAÇÃO DE REGRAS (Transações já vinculadas) ---
      if (regraAtual && regraAtual != 0 && regraAtual != "0" && regraAtual != 2106) {
        const regraVinculada = regrasMap.get(Number(regraAtual));

        if (regraVinculada) {
          const precisaAtualizar =
            String(regraVinculada.categoria || "0") !== String(transacao.categoria || "0") ||
            String(regraVinculada.beneficiario_pagador || "0") !== String(transacao.beneficiario_pagador || "0") ||
            String(regraVinculada.caixinha || "0") !== String(transacao.caixinha || "0");

          if (precisaAtualizar) {
            updates.push(prepararUpdate(idExtrato, regraVinculada));
          }
        } else {
          // REGRA DELETADA: Limpa os dados se o ID da regra não existe mais no sistema
          const regraReset = {
            idregras_financeiro: "0",
            categoria: "0",
            beneficiario_pagador: "0",
            caixinha: "0"
          };
          updates.push(prepararUpdate(idExtrato, regraReset));
        }

        processadas++;
        if (onProgress) onProgress(processadas, total);
        continue;
      }

      // --- LÓGICA 2: CONCILIAÇÃO POR REGRAS EXISTENTES (Transações sem regra) ---
      let regraEncontrada = null;
      for (const regra of regrasLista) {
        if (descricaoNorm.includes(regra.condNorm)) {
          regraEncontrada = regra;
          break;
        }
      }

      if (regraEncontrada) {
        const jaConciliadoComEstaRegra =
          String(regraEncontrada.categoria || "0") === String(transacao.categoria || "0") &&
          String(regraEncontrada.beneficiario_pagador || "0") === String(transacao.beneficiario_pagador || "0");

        if (!jaConciliadoComEstaRegra) {
          updates.push(prepararUpdate(idExtrato, regraEncontrada));
        }

        processadas++;
        if (onProgress) onProgress(processadas, total);
        continue;
      }

      // --- LÓGICA 3: CONCILIAÇÃO INTELIGENTE DE EMPRESAS (Scoring) ---
      // Comentada por enquanto, pode ser implementada depois
      // const docExtrato = (transacao.cpfCnpjPagador || transacao.cpfCnpjRecebedor || "").replace(/\D/g, '');
      // let empresaMatch = docExtrato ? empresasCpfMap.get(docExtrato) : null;
      // ... (lógica de matching por empresa)

      processadas++;
      if (onProgress) onProgress(processadas, total);
    }

    console.groupEnd();

    // 4. Execução de Updates (Batching via Promise.all)
    let erros = 0;
    if (updates.length > 0) {
      console.log(`[reconciliationEngine] 🚀 Enviando ${updates.length} atualizações...`);

      // Processa em lotes de 10 para não sobrecarregar o servidor
      const batchSize = 10;
      for (let i = 0; i < updates.length; i += batchSize) {
        const batch = updates.slice(i, i + batchSize);
        try {
          await Promise.all(batch.map(up => executarUpdates(up)));
          console.log(`[reconciliationEngine] Lote ${Math.floor(i / batchSize) + 1} concluído (${batch.length} transações)`);
        } catch (error) {
          console.error(`[reconciliationEngine] Erro no lote ${Math.floor(i / batchSize) + 1}:`, error);
          erros += batch.length;
        }
      }
    }

    console.timeEnd("⏱️ Tempo Total de Conciliação");
    console.log('[reconciliationEngine] ========== CONCILIAÇÃO CONCLUÍDA ==========');
    console.log('[reconciliationEngine] Resultado:', {
      processadas,
      atualizadas: updates.length,
      erros
    });

    return {
      sucesso: true,
      processados: processadas,
      atualizados: updates.length,
      erros
    };
  } catch (error) {
    console.error('[reconciliationEngine] ========== ERRO NA CONCILIAÇÃO ==========');
    console.error('[reconciliationEngine] Erro:', error);
    console.timeEnd("⏱️ Tempo Total de Conciliação");

    throw error;
  }
};

/**
 * Reseta todas as transações (remove categorização e regras)
 * 
 * @param {Object} options - Opções de reset
 * @param {Function} [options.onProgress] - Callback de progresso (processados, total)
 * @returns {Promise<Object>} - Resultado do reset { sucesso, processados, erros }
 */
export const resetarTodasTransacoes = async ({ onProgress } = {}) => {
  console.time("⏱️ Tempo de Reset");
  console.log('[reconciliationEngine] ========== INICIANDO RESET DE TRANSAÇÕES ==========');

  try {
    // 1. Busca todas as transações
    const extratoRes = await conciliacaoService.fetchStatement();
    const Extrato = toArray(extratoRes);

    if (Extrato.length === 0) {
      console.log("[reconciliationEngine] Nenhuma transação encontrada para resetar.");
      return { sucesso: true, processados: 0, erros: 0 };
    }

    console.log(`[reconciliationEngine] 🧹 Iniciando reset de ${Extrato.length} transações...`);

    // 2. Prepara o objeto de reset
    const prepararReset = (id) => ({
      idextrato: id,
      regra: "0",
      categoria: "0",
      beneficiario_pagador: "0",
      caixinha: "0",
      Resutl: true
    });

    // 3. Prepara todos os updates
    const updates = Extrato
      .map(t => t.idextrato || t.id)
      .filter(id => id)
      .map(id => prepararReset(id));

    let erros = 0;
    const total = updates.length;

    // 4. Execução em Lote (Batching para não sobrecarregar)
    const batchSize = 10;
    for (let i = 0; i < updates.length; i += batchSize) {
      const batch = updates.slice(i, i + batchSize);
      try {
        await Promise.all(batch.map(objeto => executarUpdates(objeto)));
        console.log(`[reconciliationEngine] Lote ${Math.floor(i / batchSize) + 1} resetado (${batch.length} transações)`);

        if (onProgress) {
          onProgress(Math.min(i + batchSize, total), total);
        }
      } catch (error) {
        console.error(`[reconciliationEngine] Erro no lote ${Math.floor(i / batchSize) + 1}:`, error);
        erros += batch.length;
      }
    }

    console.log("[reconciliationEngine] ✅ Reset concluído com sucesso!");
    console.timeEnd("⏱️ Tempo de Reset");
    console.log('[reconciliationEngine] Resultado:', {
      processados: total,
      erros
    });

    return {
      sucesso: true,
      processados: total,
      erros
    };
  } catch (error) {
    console.error("[reconciliationEngine] ❌ Erro durante o reset massivo:", error);
    console.timeEnd("⏱️ Tempo de Reset");
    throw error;
  }
};
