import { Product, ProductColorVariant } from '@/types'; import { generateAttractiveProductCopy } from './attractive-copy'; import { getProductSocialProof } from './social-proof'; /** * Normaliza el nombre del modelo para identificar automáticamente productos del mismo modelo * pero con diferente colorway (ej: "Adidas Samba", "Adidas Samba Blanco y Negro", "Adidas Samba Gum") */ export function normalizeModelKey(name: string, brand?: string): string { let clean = (name || '').toLowerCase(); if (brand) { const b = brand.toLowerCase(); if (!clean.includes(b)) clean = `${b} ${clean}`; } clean = clean .replace( /\b(blanco|negro|gris|azul|verde|rojo|rosa|beige|gum|cream|shadow|panda|retro|og|h|dama|caballero|unisex|ref|\d{3}-\d{3}|edition|edicion|clasico|clasica|sneakers|zapatillas|calzado|para|de|y|en|con)\b/gi, '' ) .replace(/[^a-z0-9\s]/g, '') .replace(/\s+/g, '-') .replace(/^-+|-+$/g, ''); return clean || 'sneakers'; } /** * Agrupa una lista de productos que corresponden al mismo modelo pero diferente color * Convirtiéndolos en un único producto con múltiples colorways (ProductColorVariant). */ export function groupProductsByModel(products: Product[]): Product[] { const modelMap = new Map(); for (const prod of products) { const brand = prod.brand || 'Sneakers'; const baseModelName = prod.modelName || prod.name; const modelKey = normalizeModelKey(baseModelName, brand); if (!modelMap.has(modelKey)) { // Inicializar el primer producto para este modelo const colors: ProductColorVariant[] = Array.isArray(prod.colors) && prod.colors.length > 0 ? [...prod.colors] : [ { id: `color-${Date.now()}-1`, colorName: prod.colorName || 'Estilo Principal', image: prod.images[0], images: prod.images, sizes: prod.sizes || ['37', '38', '39', '40', '41', '42', '43'], inStock: prod.inStock !== false, }, ]; const proof = getProductSocialProof(prod); modelMap.set(modelKey, { ...prod, modelName: baseModelName, colors, description: prod.description || generateAttractiveProductCopy(prod), rating: prod.rating || proof.rating, reviewsCount: prod.reviewsCount || proof.reviewsCount, salesCount: prod.salesCount || proof.salesCount, }); } else { // El modelo ya existe: fusionar colorways, fotos y tallas const existing = modelMap.get(modelKey)!; const existingColors = existing.colors || []; // Extraer los colorways del nuevo producto const incomingColors: ProductColorVariant[] = Array.isArray(prod.colors) && prod.colors.length > 0 ? prod.colors : [ { id: `color-${Date.now()}-${existingColors.length + 1}`, colorName: prod.colorName || `Estilo #${existingColors.length + 1}`, image: prod.images[0], images: prod.images, sizes: prod.sizes || ['37', '38', '39', '40', '41', '42', '43'], inStock: prod.inStock !== false, }, ]; // Agregar colorways que no estén ya presentes (por URL de imagen) incomingColors.forEach((inc) => { const isDuplicate = existingColors.some( (ec) => ec.image === inc.image || ec.colorName.toLowerCase() === inc.colorName.toLowerCase() ); if (!isDuplicate) { existingColors.push({ ...inc, id: inc.id || `color-${Date.now()}-${existingColors.length + 1}`, }); } }); // Fusionar imágenes sin duplicados const mergedImages = Array.from(new Set([...existing.images, ...prod.images])); // Fusionar tallas sin duplicados const mergedSizes = Array.from(new Set([...existing.sizes, ...(prod.sizes || [])])).sort( (a, b) => parseInt(a, 10) - parseInt(b, 10) ); existing.colors = existingColors; existing.images = mergedImages; existing.sizes = mergedSizes; } } return Array.from(modelMap.values()); }