import { useState, useEffect, useMemo, useCallback } from 'react';
import { extratoService } from '@/services/extratoService';

/**
 * Retorna o último saldo armazenado (mais recente por data).
 * Usado como "último saldo do mês passado" no cruzamento do fluxo de caixa.
 * @param {Array<{ data?, data_saldo?, saldo }>} saldosArmazenados
 * @returns {number}
 */
function getUltimoSaldoArmazenado(saldosArmazenados) {
  if (!Array.isArray(saldosArmazenados) || saldosArmazenados.length === 0) return 0;
  const comData = saldosArmazenados
    .map((item) => ({
      ...item,
      data: item.data ?? item.data_saldo ?? item.dataSaldo,
      saldo: Number(item.saldo) || 0
    }))
    .filter((item) => item.data);
  if (comData.length === 0) return Number(saldosArmazenados[0]?.saldo) || 0;
  comData.sort((a, b) => new Date(b.data) - new Date(a.data));
  return comData[0].saldo;
}

/**
 * Hook para Fluxo de Caixa (financeiro_v2).
 * Cruzamento: Último saldo (armazenado) + Receitas (extrato C) − Despesas (extrato D) = Resultado
 * O resultado deve coincidir com o Saldo disponível (/saldo).
 */
export function useFluxoCaixa() {
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
  const [extrato, setExtrato] = useState([]);
  const [saldo, setSaldo] = useState({ disponivel: 0 });
  const [saldoArmazenado, setSaldoArmazenado] = useState([]);
  const [fluxoData, setFluxoData] = useState({ mensal: [] });
  const [somaCategoria, setSomaCategoria] = useState({ por_categoria: [] });
  const [saldoConsolidado, setSaldoConsolidado] = useState(null);
  const [porCaixinha, setPorCaixinha] = useState([]);
  
  const [filtroMes, setFiltroMes] = useState(String(new Date().getMonth() + 1));
  const [filtroAno, setFiltroAno] = useState(new Date().getFullYear().toString());
  const [filtroTipo, setFiltroTipo] = useState('mes'); // 'mes' | 'ano' | 'todos'

  const loadData = useCallback(async () => {
    try {
      setLoading(true);
      setError(null);
      
      const mesAtu = filtroMes;
      const anoAtu = filtroAno;
      const tipo = filtroTipo;

      // Monta os parâmetros de forma dinâmica conforme o tipo de filtro
      const params = {};
      if (tipo === 'mes') {
        params.mes = mesAtu;
        params.ano = anoAtu;
      } else if (tipo === 'ano') {
        params.ano = anoAtu;
      }
      // Se for 'todos', params fica vazio

      const [extratoData, saldoData, armazenadoData, fluxoResponse, somaCategoriaData, consolidadoData, caixinhasList, categoriasList] = await Promise.all([
        extratoService.fetchExtrato(params),
        extratoService.fetchSaldo(),
        extratoService.fetchSaldoArmazenado(),
        extratoService.fetchFluxo(params),
        extratoService.getSomaPorCategoria(params),
        extratoService.fetchSaldoConsolidado(params),
        extratoService.fetchCaixinhas(),
        extratoService.fetchCategorias()
      ]);

      // --- CLIENT-SIDE FILTERING FALLBACK ---
      const matchesPeriod = (itemDate) => {
        if (!itemDate || tipo === 'todos') return true;
        
        // formats: YYYY-MM-DD or DD/MM/YYYY or ISO or "Wed, 11 Feb 2026 00:00:00 GMT"
        let d;
        if (typeof itemDate === 'string') {
          if (itemDate.includes('/')) {
            const parts = itemDate.split('/');
            const day = parts[0];
            const month = parts[1];
            // Handle if there's a time after the year: "2026 11:30"
            const yearPart = parts[2] || '';
            const year = yearPart.split(' ')[0];
            
            d = new Date(year, month - 1, day);
          } else {
            d = new Date(itemDate);
          }
        } else {
          d = new Date(itemDate);
        }

        if (!d || Number.isNaN(d.getTime())) return false;

        const itemMonth = String(d.getMonth() + 1);
        const itemYear = String(d.getFullYear());

        if (tipo === 'mes') {
          return itemMonth === mesAtu && itemYear === anoAtu;
        } else if (tipo === 'ano') {
          return itemYear === anoAtu;
        }
        return true;
      };

      // 0. Build Comprehensive Categories Map
      const categoriesMap = {};
      
      // Source A: /categorias/apresentar
      if (Array.isArray(categoriasList)) {
        categoriasList.forEach(c => {
          const cId = String(c.idcategoria ?? c.idcategorias ?? c.id ?? '');
          if (cId) {
            categoriesMap[cId] = c.categoria || c.name || c.nome || c.descricao;
          }
        });
      }

      // Source B: Labels already in /extrato/soma_por_categoria
      const rawPorCategoria = somaCategoriaData?.por_categoria || [];
      rawPorCategoria.forEach(cat => {
        const cId = String(cat.idcategoria ?? '');
        if (cId && cat.categoria && isNaN(cat.categoria)) {
          if (!categoriesMap[cId] || categoriesMap[cId].startsWith('Categoria ')) {
            categoriesMap[cId] = cat.categoria;
          }
        }
      });

      // 1. Process Extrato (Table Data) - Consolidate labels
      const rawExtrato = Array.isArray(extratoData) ? extratoData : [];
      const filteredExtrato = rawExtrato.filter(item => 
        matchesPeriod(item.dataEntrada || item.data || item.data_entrada)
      );

      setExtrato(filteredExtrato.map(item => {
        // ID can be in 'categoria' or 'idcategoria'
        let idVal = item.idcategoria || '';
        if (!idVal && item.categoria && !isNaN(item.categoria)) idVal = item.categoria;
        const id = String(idVal || '0');
        
        const catName = categoriesMap[id] || 
                        item.categoria_nome || 
                        (isNaN(item.categoria) ? item.categoria : null) || 
                        (id === '0' ? 'Sem Categoria' : `Categoria ${id}`);
        
        return {
          ...item,
          categoria_nome: catName
        };
      }));

      // 2. Aggregate Categories (Chart Data) - Unified C and D for the same category
      const aggregatedSummary = {};
      rawPorCategoria.forEach(cat => {
        const id = String(cat.idcategoria ?? '0');
        const name = categoriesMap[id] || cat.categoria || (id === '0' ? 'Sem Categoria' : `Categoria ${id}`);
        
        if (!aggregatedSummary[id]) {
          aggregatedSummary[id] = {
            idcategoria: id,
            categoria: name,
            total_entradas: 0,
            total_saidas: 0,
            total: 0,
            total_transacoes: 0
          };
        }

        const value = Math.abs(Number(cat.total) || 0);
        if (cat.tipoOperacao === 'C') {
          aggregatedSummary[id].total_entradas += value;
        } else {
          aggregatedSummary[id].total_saidas += value;
        }
        aggregatedSummary[id].total += value;
        aggregatedSummary[id].total_transacoes += Number(cat.total_transacoes || 0);
      });

      setSomaCategoria({ 
        por_categoria: Object.values(aggregatedSummary).sort((a, b) => b.total - a.total)
      });

      // 3. Process Caixinhas
      const caixinhasMap = {};
      if (Array.isArray(caixinhasList)) {
        caixinhasList.forEach(c => {
          caixinhasMap[String(c.idcaixinhas_financeiro || c.id)] = c.caixinha || c.name;
        });
      }

      const groupedCaixinha = {};
      filteredExtrato.forEach(item => {
        const id = String(item.caixinha || '0');
        if (!groupedCaixinha[id]) {
          groupedCaixinha[id] = {
            id: id,
            caixinha: caixinhasMap[id] || (id === '0' ? '(sem caixinha)' : `Caixinha ${id}`),
            total_entradas: 0,
            total_saidas: 0,
            total: 0,
            diferenca: 0
          };
        }

        const value = Math.abs(Number(item.valor) || 0);
        if (item.tipoOperacao === 'C') {
          groupedCaixinha[id].total_entradas += value;
        } else {
          groupedCaixinha[id].total_saidas += value;
        }
        groupedCaixinha[id].total = groupedCaixinha[id].total_entradas + groupedCaixinha[id].total_saidas;
        groupedCaixinha[id].diferenca = groupedCaixinha[id].total_entradas - groupedCaixinha[id].total_saidas;
      });

      setPorCaixinha(Object.values(groupedCaixinha).sort((a, b) => b.total - a.total));

      setSaldo(saldoData || { disponivel: 0 });
      setSaldoArmazenado(Array.isArray(armazenadoData) ? armazenadoData : []);
      
      const filteredFluxo = {
        mensal: (fluxoResponse?.mensal || []).filter(item => {
          if (tipo === 'ano') return String(item.ano) === anoAtu;
          return true;
        }),
        diario: (fluxoResponse?.diario || []).filter(item => {
          if (tipo === 'mes') return String(item.mes) === mesAtu && String(item.ano) === anoAtu;
          return true;
        }),
        anual: fluxoResponse?.anual || []
      };
      setFluxoData(filteredFluxo);
      setSaldoConsolidado(consolidadoData || null);
    } catch (err) {
      console.error('[useFluxoCaixa] Erro ao carregar dados:', err);
      setError(err.message || 'Erro ao carregar fluxo de caixa');
      setExtrato([]);
      setSaldo({ disponivel: 0 });
      setSaldoArmazenado([]);
      setFluxoData({ mensal: [] });
      setSomaCategoria({ por_categoria: [] });
      setPorCaixinha([]);
      setSaldoConsolidado(null);
    } finally {
      setLoading(false);
    }
  }, [filtroMes, filtroAno, filtroTipo]);

  useEffect(() => {
    loadData();
  }, [loadData]);

  const receitas = useMemo(() => {
    return extrato
      .filter((item) => item.tipoOperacao === 'C')
      .reduce((acc, item) => acc + Math.abs(Number(item.valor) || 0), 0);
  }, [extrato]);

  const despesas = useMemo(() => {
    return extrato
      .filter((item) => item.tipoOperacao === 'D')
      .reduce((acc, item) => acc + Math.abs(Number(item.valor) || 0), 0);
  }, [extrato]);

  const ultimoSaldo = useMemo(
    () => getUltimoSaldoArmazenado(saldoArmazenado),
    [saldoArmazenado]
  );

  const resultadoCruzamento = useMemo(() => {
    return ultimoSaldo + receitas - despesas;
  }, [ultimoSaldo, receitas, despesas]);

  /** Card Receitas: total receitas (extrato C) + último saldo do mês passado. Reflete "entradas" para o saldo atual. */
  const receitasCard = useMemo(() => ultimoSaldo + receitas, [ultimoSaldo, receitas]);

  const saldoDisponivel = useMemo(() => {
    const d = saldo?.disponivel;
    return typeof d === 'number' ? d : Number(d) || 0;
  }, [saldo]);

  const bateComSaldo = useMemo(() => {
    const diff = Math.abs(resultadoCruzamento - saldoDisponivel);
    return diff < 0.01;
  }, [resultadoCruzamento, saldoDisponivel]);

  /**
   * Transforma dados de fluxo para o formato Recharts
   * Processa tanto mensal quanto anual se disponível
   */
  const getChartData = useCallback((type = 'mensal') => {
    const data = fluxoData[type] || [];
    
    // Agrupa por período (mês, ano ou dia) e tipo de operação
    const periodGroups = data.reduce((acc, item) => {
      let key = '';
      let label = '';

      if (type === 'diario') {
        key = `${item.ano}-${String(item.mes).padStart(2, '0')}-${String(item.dia).padStart(2, '0')}`;
        label = `${String(item.dia).padStart(2, '0')}/${String(item.mes).padStart(2, '0')}`;
      } else if (type === 'mensal') {
        key = `${item.ano}-${String(item.mes).padStart(2, '0')}`;
        label = `${item.mes}/${item.ano}`;
      } else {
        key = `${item.ano}`;
        label = `${item.ano}`;
      }
      
      if (!acc[key]) {
        acc[key] = { 
          name: label,
          periodo: key,
          receitas: 0, 
          despesas: 0 
        };
      }
      
      const valor = Math.abs(Number(item.total) || 0);
      if (item.tipoOperacao === 'C') acc[key].receitas += valor;
      if (item.tipoOperacao === 'D') acc[key].despesas += valor;
      
      return acc;
    }, {});

    return Object.values(periodGroups).sort((a, b) => a.periodo.localeCompare(b.periodo));
  }, [fluxoData]);

  return {
    loading,
    error,
    extrato,
    receitas,
    receitasCard,
    despesas,
    ultimoSaldo,
    resultadoCruzamento,
    saldoDisponivel,
    bateComSaldo,
    getChartData,
    somaCategoria,
    porCaixinha,
    saldoConsolidado,
    filtroMes,
    setFiltroMes,
    filtroAno,
    setFiltroAno,
    filtroTipo,
    setFiltroTipo,
    reload: loadData
  };
}
