import { useState, useEffect, useCallback } from 'react'; import { supabase } from '@/integrations/supabase/client'; import { toast } from 'sonner'; import { useAuth } from '@/hooks/useAuth'; export interface Peca { id: string; created_at: string; of_number: string; etapa_fase: string; marca: string; descricao: string; quantidade: number; peso_unitario: number; peso_total: number; tratamento_superficial: string; material: string; perfil_principal: string; tem_componentes: boolean; user_id: string; prioridade: string; quantidadeDisponivel?: number; } interface PecaPrioridade { peca_id: string; prioridade_mais_alta: string; } export function usePecas() { const { user } = useAuth(); const [pecas, setPecas] = useState([]); const [loading, setLoading] = useState(true); const [ofNumbers, setOfNumbers] = useState([]); const [hasRecentImport, setHasRecentImport] = useState(false); const loadPecas = useCallback(async () => { console.log('šŸ”„ Carregando peƧas...'); try { const { data, error } = await supabase .from('pecas') .select('*') .order('created_at', { ascending: false }); if (error) { console.error('āŒ Erro ao carregar peƧas:', error); throw error; } console.log('āœ… PeƧas carregadas:', data?.length || 0); setPecas(data || []); const uniqueOFs = Array.from(new Set(data?.map(peca => peca.of_number).filter(Boolean) || [])); setOfNumbers(uniqueOFs); return data || []; } catch (error) { console.error('āŒ Erro ao carregar peƧas:', error); toast.error('Erro ao carregar peƧas'); return []; } }, []); const sincronizarPrioridades = useCallback(async (showToast = true) => { try { console.log('šŸ”„ Sincronizando prioridades...'); const { data: pecasComPrioridades, error } = await supabase .rpc('calcular_prioridades_pecas_bulk') as { data: PecaPrioridade[] | null, error: any }; if (error) { console.error('āŒ Erro ao calcular prioridades:', error); return; } console.log('āœ… Prioridades calculadas:', pecasComPrioridades?.length || 0); if (pecasComPrioridades && Array.isArray(pecasComPrioridades) && pecasComPrioridades.length > 0) { const updates = pecasComPrioridades.map(p => ({ id: p.peca_id, prioridade: p.prioridade_mais_alta })); const batchSize = 100; for (let i = 0; i < updates.length; i += batchSize) { const batch = updates.slice(i, i + batchSize); for (const update of batch) { const { error: updateError } = await supabase .from('pecas') .update({ prioridade: update.prioridade }) .eq('id', update.id); if (updateError) { console.error('āŒ Erro ao atualizar prioridade da peƧa:', updateError); } } } console.log('āœ… Prioridades sincronizadas com sucesso'); return await loadPecas(); } } catch (error) { console.error('āŒ Erro ao sincronizar prioridades:', error); if (showToast) { toast.error('Erro ao sincronizar prioridades'); } } }, [loadPecas]); // Carregamento inicial otimizado - sem sincronização automĆ”tica useEffect(() => { const initializeData = async () => { try { setLoading(true); console.log('šŸš€ Iniciando carregamento da tela Cadastro de PeƧas...'); // Apenas carrega as peƧas inicialmente await loadPecas(); console.log('āœ… Carregamento inicial concluĆ­do'); } catch (error) { console.error('āŒ Erro no carregamento inicial:', error); } finally { setLoading(false); } }; initializeData(); }, [loadPecas]); // Listeners otimizados - menos triggers automĆ”ticos useEffect(() => { const channel = supabase .channel('pecas_changes') .on('postgres_changes', { event: '*', schema: 'public', table: 'pecas' }, (payload) => { console.log('šŸ“” MudanƧa detectada em pecas:', payload); // Apenas recarrega se nĆ£o for atualização de prioridade if (payload.eventType !== 'UPDATE' || !payload.new?.prioridade) { if (!loading) { loadPecas(); } } }) .subscribe(); return () => { supabase.removeChannel(channel); }; }, [loading, loadPecas]); const checkRecentImport = useCallback(async () => { try { const { data, error, count } = await supabase .from('pecas') .select('*', { count: 'exact', head: true }) .eq('user_id', user?.id) .gte('created_at', new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString()); if (error) { console.error("Erro ao verificar importação recente:", error); return; } setHasRecentImport(count !== null && count > 0); console.log(`Importação recente detectada: ${count !== null && count > 0}`); } catch (error) { console.error("Erro ao verificar importação recente:", error); } }, [user?.id]); const savePeca = async (pecaData: any): Promise => { if (!user) { toast.error('UsuĆ”rio nĆ£o autenticado'); return false; } try { const { prioridade, ...cleanedData } = pecaData; const { data, error } = await supabase .from('pecas') .insert([{ ...cleanedData, user_id: user.id, prioridade: 'P4' }]) .select(); if (error) { console.error('Erro ao salvar peƧa:', error); toast.error('Erro ao salvar peƧa'); return false; } toast.success('PeƧa salva com sucesso!'); // Sincronização manual apenas quando necessĆ”rio setTimeout(() => { sincronizarPrioridades(false); }, 2000); await loadPecas(); return true; } catch (error) { console.error('Erro ao salvar peƧa:', error); toast.error('Erro ao salvar peƧa'); return false; } }; const updatePeca = async (id: string, pecaData: any): Promise => { if (!user) { toast.error('UsuĆ”rio nĆ£o autenticado'); return false; } try { const { prioridade, ...cleanedData } = pecaData; const { data, error } = await supabase .from('pecas') .update(cleanedData) .eq('id', id) .select(); if (error) { console.error('Erro ao atualizar peƧa:', error); toast.error('Erro ao atualizar peƧa'); return false; } toast.success('PeƧa atualizada com sucesso!'); // Sincronização manual apenas quando necessĆ”rio setTimeout(() => { sincronizarPrioridades(false); }, 2000); await loadPecas(); return true; } catch (error) { console.error('Erro ao atualizar peƧa:', error); toast.error('Erro ao atualizar peƧa'); return false; } }; const deletePeca = async (pecaId: string): Promise => { if (!user) { toast.error('UsuĆ”rio nĆ£o autenticado'); return false; } try { const { error } = await supabase .from('pecas') .delete() .eq('id', pecaId); if (error) { console.error('Erro ao apagar peƧa:', error); toast.error('Erro ao apagar peƧa'); return false; } toast.success('PeƧa apagada com sucesso!'); await loadPecas(); return true; } catch (error) { console.error('Erro ao apagar peƧa:', error); toast.error('Erro ao apagar peƧa'); return false; } }; const importCSV = async (file: File) => { console.log('šŸ“„ Importando CSV...'); if (!user) { toast.error('UsuĆ”rio nĆ£o autenticado'); return; } try { const text = await file.text(); const lines = text.split('\n').filter(line => line.trim()); if (lines.length < 2) { toast.error('Arquivo CSV vazio ou invĆ”lido'); return; } const headers = lines[0].split(',').map(h => h.trim()); const pecasData = []; for (let i = 1; i < lines.length; i++) { const values = lines[i].split(',').map(v => v.trim()); if (values.length === headers.length) { const peca: any = { user_id: user.id, prioridade: 'P4' }; headers.forEach((header, index) => { const value = values[index]; if (header === 'quantidade' || header === 'peso_unitario' || header === 'peso_total') { peca[header] = parseFloat(value) || 0; } else if (header === 'tem_componentes') { peca[header] = ['true', '1', 'sim'].includes(value.toLowerCase()); } else if (header !== 'prioridade') { peca[header] = value; } }); pecasData.push(peca); } } if (pecasData.length === 0) { toast.error('Nenhuma peƧa vĆ”lida encontrada no arquivo CSV'); return; } const { error } = await supabase .from('pecas') .insert(pecasData); if (error) { console.error('āŒ Erro ao importar CSV:', error); throw error; } console.log('āœ… CSV importado com sucesso:', pecasData.length, 'peƧas'); toast.success(`${pecasData.length} peƧa(s) importada(s) com sucesso!`); setHasRecentImport(true); // Sincronização manual apenas após importação setTimeout(() => { sincronizarPrioridades(false); }, 3000); await loadPecas(); } catch (error) { console.error('āŒ Erro ao importar CSV:', error); toast.error('Erro ao importar arquivo CSV'); throw error; } }; const importPecas = async (pecasData: any[]) => { console.log('šŸ“¦ Iniciando importação de peƧas:', pecasData.length); if (!user) { toast.error('UsuĆ”rio nĆ£o autenticado'); return; } try { const pecasMap = new Map(); const componentesMap = new Map(); console.log('šŸ” Separando dados de peƧas e componentes...'); pecasData.forEach((item, index) => { console.log(`šŸ“‹ Processando item ${index + 1}:`, item); const pecaKey = `${item.of_number || ''}-${item.etapa_fase || ''}-${item.marca || ''}`; const pecaData = { of_number: item.of_number || '', etapa_fase: item.etapa_fase || '', marca: item.marca || '', descricao: item.descricao || '', quantidade: Number(item.quantidade) || 0, peso_unitario: Number(item.peso_unitario) || 0, peso_total: Number(item.peso_total) || 0, tratamento_superficial: item.tratamento_superficial || '', material: item.material || '', perfil_principal: item.perfil_principal || '', tem_componentes: Boolean(item.tem_componentes), user_id: user.id, prioridade: 'P4' }; if (!pecasMap.has(pecaKey)) { pecasMap.set(pecaKey, pecaData); } if (item.marca_componente && item.marca_componente.trim()) { const componenteData = { marca_componente: item.marca_componente.trim(), descricao: item.descricao_componente || '', perfil: item.perfil_componente || '', peso_unitario: Number(item.peso_unitario_componente) || 0, quantidade_por_peca: Number(item.quantidade_por_peca) || 1, user_id: user.id }; if (!componentesMap.has(pecaKey)) { componentesMap.set(pecaKey, []); } componentesMap.get(pecaKey)!.push(componenteData); } }); const pecasParaInserir = Array.from(pecasMap.values()); console.log('āœ… PeƧas para inserir:', pecasParaInserir.length); console.log('āœ… PeƧas com componentes:', componentesMap.size); if (pecasParaInserir.length === 0) { toast.error('Nenhuma peƧa vĆ”lida encontrada para importação'); return; } console.log('šŸ’¾ Inserindo peƧas principais...'); const { data: pecasInseridas, error: pecasError } = await supabase .from('pecas') .insert(pecasParaInserir) .select('id, of_number, etapa_fase, marca'); if (pecasError) { console.error('āŒ Erro ao inserir peƧas:', pecasError); toast.error(`Erro ao inserir peƧas: ${pecasError.message}`); throw pecasError; } console.log('āœ… PeƧas inseridas com sucesso:', pecasInseridas?.length || 0); let totalComponentesInseridos = 0; if (componentesMap.size > 0 && pecasInseridas) { console.log('šŸ”§ Inserindo componentes...'); for (const [pecaKey, componentes] of componentesMap.entries()) { const [of_number, etapa_fase, marca] = pecaKey.split('-'); const pecaInserida = pecasInseridas.find(p => p.of_number === of_number && p.etapa_fase === etapa_fase && p.marca === marca ); if (pecaInserida && componentes.length > 0) { const componentesComPecaId = componentes.map(comp => ({ ...comp, peca_id: pecaInserida.id })); console.log(`šŸ”§ Inserindo ${componentesComPecaId.length} componentes para peƧa ${marca}...`); const { error: componentesError } = await supabase .from('componentes_peca') .insert(componentesComPecaId); if (componentesError) { console.error('āŒ Erro ao inserir componentes:', componentesError); } else { totalComponentesInseridos += componentesComPecaId.length; console.log(`āœ… Componentes inseridos para peƧa ${marca}: ${componentesComPecaId.length}`); } } } } let successMessage = `āœ… ${pecasInseridas?.length || 0} peƧa(s) importada(s) com sucesso!`; if (totalComponentesInseridos > 0) { successMessage += ` ${totalComponentesInseridos} componente(s) tambĆ©m foram criados.`; } console.log('šŸŽ‰ Importação concluĆ­da:', successMessage); toast.success(successMessage); setHasRecentImport(true); // Sincronização manual apenas após importação setTimeout(() => { sincronizarPrioridades(false); }, 3000); await loadPecas(); } catch (error) { console.error('āŒ Erro ao importar peƧas:', error); toast.error(`Erro ao importar peƧas: ${error instanceof Error ? error.message : 'Erro desconhecido'}`); throw error; } }; const undoLastImport = async () => { if (!user) { toast.error('UsuĆ”rio nĆ£o autenticado'); return; } try { const { data: pecasParaApagar, error: selectError } = await supabase .from('pecas') .select('id') .eq('user_id', user.id) .gte('created_at', new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString()); if (selectError) { console.error('Erro ao selecionar peƧas para apagar:', selectError); toast.error('Erro ao selecionar peƧas para apagar'); return; } if (!pecasParaApagar || pecasParaApagar.length === 0) { toast.info('Nenhuma peƧa recente para desfazer a importação.'); return; } const pecaIds = pecasParaApagar.map(peca => peca.id); const { error: deleteComponentesError } = await supabase .from('componentes_peca') .delete() .in('peca_id', pecaIds); if (deleteComponentesError) { console.error('Erro ao apagar componentes das peƧas:', deleteComponentesError); toast.error('Erro ao apagar componentes das peƧas'); return; } const { error: deleteError } = await supabase .from('pecas') .delete() .in('id', pecaIds); if (deleteError) { console.error('Erro ao apagar peƧas:', deleteError); toast.error('Erro ao apagar peƧas'); return; } toast.success('Última importação desfeita com sucesso!'); setHasRecentImport(false); await loadPecas(); } catch (error) { console.error('Erro ao desfazer importação:', error); toast.error('Erro ao desfazer importação'); } }; const deleteLastImport = async () => { if (!user) { toast.error('UsuĆ”rio nĆ£o autenticado'); return; } try { const { data: pecasParaApagar, error: selectError } = await supabase .from('pecas') .select('id') .eq('user_id', user.id) .gte('created_at', new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString()); if (selectError) { console.error('Erro ao selecionar peƧas para apagar:', selectError); toast.error('Erro ao selecionar peƧas para apagar'); return; } if (!pecasParaApagar || pecasParaApagar.length === 0) { toast.info('Nenhuma peƧa recente para apagar.'); return; } const pecaIds = pecasParaApagar.map(peca => peca.id); const { error: deleteComponentesError } = await supabase .from('componentes_peca') .delete() .in('peca_id', pecaIds); if (deleteComponentesError) { console.error('Erro ao apagar componentes das peƧas:', deleteComponentesError); toast.error('Erro ao apagar componentes das peƧas'); return; } const { error: deleteError } = await supabase .from('pecas') .delete() .in('id', pecaIds); if (deleteError) { console.error('Erro ao apagar peƧas:', deleteError); toast.error('Erro ao apagar peƧas'); return; } toast.success('Última importação apagada com sucesso!'); setHasRecentImport(false); await loadPecas(); } catch (error) { console.error('Erro ao apagar importação:', error); toast.error('Erro ao apagar importação'); } }; const batchUpdatePecas = async (pecaIds: string[], updates: any) => { if (!user) { toast.error('UsuĆ”rio nĆ£o autenticado'); return; } try { const { prioridade, ...cleanedUpdates } = updates; const { error } = await supabase .from('pecas') .update(cleanedUpdates) .in('id', pecaIds); if (error) { console.error('Erro ao atualizar peƧas em lote:', error); toast.error('Erro ao atualizar peƧas em lote'); throw error; } toast.success(`${pecaIds.length} peƧas atualizadas com sucesso!`); // Sincronização manual apenas quando necessĆ”rio setTimeout(() => { sincronizarPrioridades(false); }, 2000); await loadPecas(); } catch (error) { console.error('Erro ao atualizar peƧas em lote:', error); toast.error('Erro ao atualizar peƧas em lote'); throw error; } }; useEffect(() => { if (user?.id) { checkRecentImport(); } }, [user?.id, checkRecentImport]); return { pecas, loading, ofNumbers, savePeca, updatePeca, deletePeca, importCSV, importPecas, undoLastImport, deleteLastImport, hasRecentImport, batchUpdatePecas, loadPecas, sincronizarPrioridades }; }