import React from 'react'; import { motion, AnimatePresence } from 'framer-motion'; import { X, ShieldCheck, Database, RefreshCw, Tag, BarChart3, ArrowRight, BadgeCheck, Download, ArrowLeftRight, Layers } from 'lucide-react'; import { useTranslation } from 'react-i18next'; import type { AnalysisData, HeatmapDataPoint } from '../types'; interface MetodologiaDrawerProps { isOpen: boolean; onClose: () => void; data: AnalysisData; } interface DataSummary { totalRegistros: number; mesesHistorico: number; periodo: string; fuente: string; taxonomia: { valid: number; noise: number; zombie: number; abandon: number; }; kpis: { fcrTecnico: number; fcrReal: number; abandonoTradicional: number; abandonoReal: number; ahtLimpio: number; skillsTecnicos: number; skillsNegocio: number; }; } // ========== SUBSECCIONES ========== function DataSummarySection({ data, t }: { data: DataSummary; t: any }) { return (

{t('methodology.dataProcessed')}

{data.totalRegistros.toLocaleString('es-ES')}
{t('methodology.recordsAnalyzed')}
{data.mesesHistorico}
{t('methodology.monthsHistory')}
{data.fuente}
{t('methodology.sourceSystem')}

{t('methodology.periodRange', { period: data.periodo })}

); } function PipelineSection({ t }: { t: any }) { const steps = [ { layer: 'Layer 0', name: t('methodology.pipeline.layer1'), desc: t('methodology.pipeline.layer1Desc'), color: 'bg-gray-100 border-gray-300' }, { layer: 'Layer 1', name: t('methodology.pipeline.layer2'), desc: t('methodology.pipeline.layer2Desc'), color: 'bg-yellow-50 border-yellow-300' }, { layer: 'Layer 2', name: t('methodology.pipeline.layer3'), desc: t('methodology.pipeline.layer3Desc'), color: 'bg-green-50 border-green-300' }, { layer: 'Output', name: t('methodology.pipeline.layer4'), desc: t('methodology.pipeline.layer4Desc'), color: 'bg-blue-50 border-blue-300' } ]; return (

{t('methodology.pipeline.title')}

{steps.map((step, index) => (
{step.layer}
{step.name}
{step.desc}
{index < steps.length - 1 && ( )}
))}

{t('methodology.pipeline.description')}

); } function TaxonomySection({ data, t }: { data: DataSummary['taxonomia']; t: any }) { const rows = [ { status: t('methodology.taxonomy.valid'), pct: data.valid, def: t('methodology.taxonomy.validDef'), costes: true, aht: true, bgClass: 'bg-green-100 text-green-800' }, { status: t('methodology.taxonomy.noise'), pct: data.noise, def: t('methodology.taxonomy.noiseDef'), costes: true, aht: false, bgClass: 'bg-yellow-100 text-yellow-800' }, { status: t('methodology.taxonomy.zombie'), pct: data.zombie, def: t('methodology.taxonomy.zombieDef'), costes: true, aht: false, bgClass: 'bg-red-100 text-red-800' }, { status: t('methodology.taxonomy.abandon'), pct: data.abandon, def: t('methodology.taxonomy.abandonDef'), costes: false, aht: false, bgClass: 'bg-gray-100 text-gray-800' } ]; return (

{t('methodology.taxonomy.title')}

{t('methodology.taxonomy.description')}

{rows.map((row, idx) => ( ))}
{t('methodology.taxonomy.state')} {t('methodology.taxonomy.percentage')} {t('methodology.taxonomy.definition')} {t('methodology.taxonomy.costs')} {t('methodology.taxonomy.aht')}
{row.status} {row.pct.toFixed(1)}% {row.def} {row.costes ? ( {t('methodology.taxonomy.sumYes')} ) : ( {t('methodology.taxonomy.sumNo')} )} {row.aht ? ( {t('methodology.taxonomy.avgYes')} ) : ( {t('methodology.taxonomy.avgExclude')} )}
); } function KPIRedefinitionSection({ kpis, t }: { kpis: DataSummary['kpis']; t: any }) { const formatTime = (seconds: number): string => { const mins = Math.floor(seconds / 60); const secs = seconds % 60; return `${mins}:${secs.toString().padStart(2, '0')}`; }; return (

{t('methodology.kpis.title')}

{t('methodology.kpis.description')}

{/* FCR */}

{t('methodology.kpis.fcrTitle')}

{t('methodology.kpis.fcrSubtitle')}

{kpis.fcrReal}%
{t('methodology.kpis.fcrTechnical')} ~{kpis.fcrTecnico}%
{t('methodology.kpis.fcrReal')} {kpis.fcrReal}%

💡 {t('methodology.kpis.fcrGap', { diff: kpis.fcrTecnico - kpis.fcrReal })}

{/* Abandono */}

{t('methodology.kpis.abandonTitle')}

{t('methodology.kpis.abandonFormula')}

{kpis.abandonoReal.toFixed(1)}%

💡 {t('methodology.kpis.abandonDesc')}

{/* AHT */}

{t('methodology.kpis.ahtTitle')}

{t('methodology.kpis.ahtDesc')}

{formatTime(kpis.ahtLimpio)}

💡 {t('methodology.kpis.ahtNote')}

); } function CPICalculationSection({ totalCost, totalVolume, costPerHour = 20, t }: { totalCost: number; totalVolume: number; costPerHour?: number; t: any }) { // Productivity factor: agents are ~70% productive (rest is breaks, training, after-call work, etc.) const effectiveProductivity = 0.70; // CPI = Total Cost / Total Volume // El coste total ya incluye: TODOS los registros (noise + zombie + valid) y el factor de productividad const cpi = totalVolume > 0 ? totalCost / totalVolume : 0; return (

{t('methodology.kpis.cpiTitle')}

{t('methodology.cpi.description', { productivity: (effectiveProductivity * 100).toFixed(0) })}

{/* Fórmula visual */}
{t('methodology.kpis.cpiFormulaTitle')}
{t('methodology.kpis.cpiLabel')} = {t('methodology.kpis.totalCost')} {t('methodology.kpis.divide')} {t('methodology.kpis.totalVolume')}

{t('methodology.kpis.cpiNote')}

{/* Cómo se calcula el coste total */}
{t('methodology.kpis.howCalculate')}
{t('methodology.kpis.costEquals')} (AHT seg ÷ 3600) × €{costPerHour}/h × {t('methodology.cpi.volume')} ÷ {(effectiveProductivity * 100).toFixed(0)}%

{t('methodology.cpi.ahtExplanation')}

{/* Componentes del coste horario */}
{t('methodology.cpi.hourlyRate')}
{t('methodology.cpi.configuredValue', { value: costPerHour.toFixed(2) })}

{t('methodology.cpi.includesAllCosts')}

• {t('methodology.cpi.cost1')}
• {t('methodology.cpi.cost2')}
• {t('methodology.cpi.cost3')}
• {t('methodology.cpi.cost4')}
• {t('methodology.cpi.cost5')}
• {t('methodology.cpi.cost6')}

💡 {t('methodology.cpi.adjustNote')}

); } function BeforeAfterSection({ kpis, t }: { kpis: DataSummary['kpis']; t: any }) { const rows = [ { metric: t('methodology.impact.fcr'), tradicional: `${kpis.fcrTecnico}%`, beyond: `${kpis.fcrReal}%`, beyondClass: 'text-red-600', impacto: t('methodology.impact.revealsDemand') }, { metric: t('methodology.impact.abandon'), tradicional: `~${kpis.abandonoTradicional}%`, beyond: `${kpis.abandonoReal.toFixed(1)}%`, beyondClass: 'text-yellow-600', impacto: t('methodology.impact.detectsFrustration') }, { metric: t('methodology.impact.skills'), tradicional: t('methodology.impact.technicalSkills', { count: kpis.skillsTecnicos }), beyond: t('methodology.impact.businessLines', { count: kpis.skillsNegocio }), beyondClass: 'text-blue-600', impacto: t('methodology.impact.executiveVision') }, { metric: t('methodology.impact.aht'), tradicional: t('methodology.impact.distorted'), beyond: t('methodology.impact.clean'), beyondClass: 'text-green-600', impacto: t('methodology.impact.reflectsPerformance') } ]; return (

{t('methodology.impact.title')}

{rows.map((row, idx) => ( ))}
{t('methodology.impact.metric')} {t('methodology.impact.traditional')} {t('methodology.impact.beyond')} {t('methodology.impact.impact')}
{row.metric} {row.tradicional} {row.beyond} {row.impacto}

💡 {t('methodology.impact.withoutTransformation')} {t('methodology.impact.wrongInvestments')}

); } function SkillsMappingSection({ numSkillsNegocio, t }: { numSkillsNegocio: number; t: any }) { const mappings = [ { lineaNegocio: t('methodology.skillMapping.baggage'), keywords: 'HANDLING, EQUIPAJE, AHL (Lost & Found), DPR (Daños)', color: 'bg-amber-100 text-amber-800' }, { lineaNegocio: t('methodology.skillMapping.sales'), keywords: 'COMPRA, VENTA, RESERVA, PAGO', color: 'bg-blue-100 text-blue-800' }, { lineaNegocio: t('methodology.skillMapping.loyalty'), keywords: 'SUMA (Programa de Fidelización)', color: 'bg-purple-100 text-purple-800' }, { lineaNegocio: t('methodology.skillMapping.b2b'), keywords: 'AGENCIAS, AAVV, EMPRESAS, AVORIS, TOUROPERACION', color: 'bg-cyan-100 text-cyan-800' }, { lineaNegocio: t('methodology.skillMapping.changes'), keywords: 'MODIFICACION, CAMBIO, POSTVENTA, REFUND, REEMBOLSO', color: 'bg-orange-100 text-orange-800' }, { lineaNegocio: t('methodology.skillMapping.digital'), keywords: 'WEB (Soporte a navegación)', color: 'bg-indigo-100 text-indigo-800' }, { lineaNegocio: t('methodology.skillMapping.customer'), keywords: 'ATENCION, INFO, OTROS, GENERAL, PREMIUM', color: 'bg-green-100 text-green-800' }, { lineaNegocio: t('methodology.skillMapping.internal'), keywords: 'COORD, BO_, HELPDESK, BACKOFFICE', color: 'bg-slate-100 text-slate-800' } ]; return (

{t('methodology.skillMapping.title')}

{/* Resumen del mapeo */}
{t('methodology.skillMapping.simplificationApplied')}
980 {numSkillsNegocio}

{t('methodology.skillMapping.reductionDesc', { count: numSkillsNegocio })}

{/* Tabla de mapeo */}
{mappings.map((m, idx) => ( ))}
{t('methodology.skillMapping.businessLine')} {t('methodology.skillMapping.keywords')}
{m.lineaNegocio} {m.keywords}

💡 {t('methodology.skillMapping.fuzzyLogicNote')}

); } function GuaranteesSection({ t }: { t: any }) { const guarantees = [ { icon: '✓', title: t('methodology.quality.traceability'), desc: t('methodology.quality.traceabilityDesc') }, { icon: '✓', title: t('methodology.quality.formulas'), desc: t('methodology.quality.formulasDesc') }, { icon: '✓', title: t('methodology.quality.reconciliation'), desc: t('methodology.quality.reconciliationDesc') }, { icon: '✓', title: t('methodology.quality.replicable'), desc: t('methodology.quality.replicableDesc') } ]; return (

{t('methodology.quality.title')}

{guarantees.map((item, i) => (
{item.icon}
{item.title}
{item.desc}
))}
); } // ========== COMPONENTE PRINCIPAL ========== export function MetodologiaDrawer({ isOpen, onClose, data }: MetodologiaDrawerProps) { const { t } = useTranslation(); // Calcular datos del resumen desde AnalysisData const totalRegistros = data.heatmapData?.reduce((sum, h) => sum + h.volume, 0) || 0; const totalCost = data.heatmapData?.reduce((sum, h) => sum + (h.annual_cost || 0), 0) || 0; // cost_volume: volumen usado para calcular coste (non-abandon), fallback a volume si no existe const totalCostVolume = data.heatmapData?.reduce((sum, h) => sum + (h.cost_volume || h.volume), 0) || totalRegistros; // Calcular meses de histórico desde dateRange let mesesHistorico = 1; if (data.dateRange?.min && data.dateRange?.max) { const minDate = new Date(data.dateRange.min); const maxDate = new Date(data.dateRange.max); mesesHistorico = Math.max(1, Math.round((maxDate.getTime() - minDate.getTime()) / (1000 * 60 * 60 * 24 * 30))); } // Calcular FCR promedio const avgFCR = data.heatmapData?.length > 0 ? Math.round(data.heatmapData.reduce((sum, h) => sum + (h.metrics?.fcr || 0), 0) / data.heatmapData.length) : 46; // Calcular abandono promedio const avgAbandonment = data.heatmapData?.length > 0 ? data.heatmapData.reduce((sum, h) => sum + (h.metrics?.abandonment_rate || 0), 0) / data.heatmapData.length : 11; // Calcular AHT promedio const avgAHT = data.heatmapData?.length > 0 ? Math.round(data.heatmapData.reduce((sum, h) => sum + (h.aht_seconds || 0), 0) / data.heatmapData.length) : 289; const dataSummary: DataSummary = { totalRegistros, mesesHistorico, periodo: data.dateRange ? `${data.dateRange.min} - ${data.dateRange.max}` : t('methodology.defaultPeriod'), fuente: data.source === 'backend' ? t('methodology.sourceGenesys') : t('methodology.sourceDataset'), taxonomia: { valid: 94.2, noise: 3.1, zombie: 0.8, abandon: 1.9 }, kpis: { fcrTecnico: Math.min(87, avgFCR + 30), fcrReal: avgFCR, abandonoTradicional: 0, abandonoReal: avgAbandonment, ahtLimpio: avgAHT, skillsTecnicos: 980, skillsNegocio: data.heatmapData?.length || 9 } }; const handleDownloadPDF = () => { // Por ahora, abrir una URL placeholder o mostrar alert alert(t('methodology.pdfDevelopment')); // En producción: window.open('/documents/Beyond_Diagnostic_Protocolo_Datos.pdf', '_blank'); }; const formatDate = (): string => { const now = new Date(); const monthKey = `methodology.months.${['january', 'february', 'march', 'april', 'may', 'june', 'july', 'august', 'september', 'october', 'november', 'december'][now.getMonth()]}`; return `${t(monthKey)} ${now.getFullYear()}`; }; return ( {isOpen && ( <> {/* Overlay */} {/* Drawer */} {/* Header */}

{t('methodology.fullTitle')}

{/* Body - Scrollable */}
{/* Footer */}
{t('methodology.certificate', { date: formatDate() })}
)}
); } export default MetodologiaDrawer;