import { NextResponse } from 'next/server'; import { dataService } from '@/lib/data-service'; import { parseSupplierMessage } from '@/lib/gemini-parser'; import { SupplierPost, Product } from '@/types'; import { calculateRetailPrice } from '@/lib/pricing-engine'; export async function GET() { const posts = dataService.getSupplierPosts(); const settings = dataService.getSettings(); return NextResponse.json({ success: true, autoPublishEnabled: settings.autoPublishSupplierPosts ?? true, postsCount: posts.length, posts, }); } export async function POST(request: Request) { try { const payload = await request.json(); console.log('📥 [WhatsApp Webhook] Mensaje recibido:', JSON.stringify(payload).slice(0, 300)); const data = payload.data || payload; const settings = dataService.getSettings(); // 1. Extraer texto del mensaje de WhatsApp const messageContent = data.message?.conversation || data.message?.extendedTextMessage?.text || data.message?.imageMessage?.caption || data.text || ''; // 2. Extraer nombre del canal o grupo const senderPhone = data.key?.remoteJid?.replace(/\D/g, '') || ''; const isGroup = data.key?.remoteJid?.includes('g.us'); const channelName = data.groupInfo?.subject || data.pushName || (isGroup ? 'Grupo Mayorista WhatsApp' : 'Chat Proveedor Directo'); if (!messageContent || messageContent.trim().length < 6) { return NextResponse.json({ success: true, ignored: 'Mensaje sin texto suficiente para extraer calzado.', }); } // 3. Buscar proveedor asociado por teléfono o grupo const suppliers = dataService.getSuppliers(); const matchedSupplier = suppliers.find( (s) => s.phone.includes(senderPhone) || (channelName && s.name.toLowerCase().includes(channelName.toLowerCase())) || (channelName && channelName.toLowerCase().includes(s.name.toLowerCase())) ); const supplierName = matchedSupplier?.name || channelName; const supplierPhone = matchedSupplier?.phone || senderPhone || '573167455877'; // 4. Procesar y extraer información con Gemini AI const extracted = await parseSupplierMessage(messageContent); // Recalcular precio con el margen y redondeo al $5.000 oficial const finalRetailPrice = calculateRetailPrice( extracted.supplierPrice, settings.defaultProfitMargin || 35 ); // Extraer imágenes (si Evolution API envió imagen adjunta o usar fotos de alta resolución) const images: string[] = []; if (data.message?.imageMessage?.url) { images.push(data.message.imageMessage.url); } else { images.push( 'https://images.unsplash.com/photo-1595950653106-6c9ebd614d3a?auto=format&fit=crop&w=800&q=80' ); } // 5. Verificar Anti-Duplicados en el Catálogo const existingProducts = dataService.getProducts(); const duplicateProduct = existingProducts.find( (p) => p.name.toLowerCase() === extracted.name.toLowerCase() ); let registeredProduct: Product | null = null; const autoPublish = settings.autoPublishSupplierPosts ?? true; if (autoPublish) { if (duplicateProduct) { // Actualizar stock y tallas existentes sin duplicar const mergedSizes = Array.from(new Set([...duplicateProduct.sizes, ...extracted.sizes])); registeredProduct = dataService.updateProduct(duplicateProduct.id, { supplierPrice: extracted.supplierPrice, retailPrice: finalRetailPrice, sizes: mergedSizes, inStock: true, isActive: true, supplierName, supplierPhone, }); console.log(`🔄 [Auto-Sync] Zapatilla "${extracted.name}" actualizada en catálogo (Anti-Duplicados).`); } else { // Registrar y publicar automáticamente registeredProduct = dataService.addProduct({ name: extracted.name, brand: extracted.brand, supplierPrice: extracted.supplierPrice, retailPrice: finalRetailPrice, originalPrice: Math.round(finalRetailPrice * 1.35), sizes: extracted.sizes, images, description: `Zapatillas ${extracted.brand} ${extracted.name} garantizadas. Calidad seleccionada con horma nacional y suela antideslizante.`, category: extracted.category || 'Sneakers / Urbano', inStock: true, isActive: true, isFlashDeal: true, rating: 4.9, reviewsCount: 15, salesCount: 30, originBadge: 'Bodega Mayorista', supplierId: matchedSupplier?.id || 'sup-auto', supplierName, supplierPhone, }); console.log(`✨ [Auto-Publish] Nueva zapatilla "${extracted.name}" publicada automáticamente en tienda.`); } } // 6. Registrar en el historial de publicaciones recibidas const newPost: SupplierPost = { id: `post-${Date.now()}`, channelName, supplierName, supplierPhone, rawMessage: messageContent, rawImages: images, extractedProduct: { ...extracted, suggestedRetailPrice: finalRetailPrice, supplierName, supplierPhone, }, status: autoPublish ? 'published_store' : 'pending_review', receivedAt: 'Justo ahora', }; dataService.addSupplierPost(newPost); return NextResponse.json({ success: true, autoPublished: autoPublish, product: registeredProduct, post: newPost, message: autoPublish ? `🔥 ¡Zapatilla "${extracted.name}" procesada y publicada AUTOMÁTICAMENTE en la tienda!` : `Mensaje ingresado al feed para aprobación manual.`, }); } catch (error: any) { console.error('Error procesando webhook de WhatsApp:', error); return NextResponse.json({ success: false, error: error.message }, { status: 500 }); } }