// utils/analytics.js - Versión mejorada
import { getCookieConsent, hasConsentFor } from './cookies';

// Configuración centralizada
const CONFIG = {
  MAX_EVENTS: 500,
  MAX_VISITS: 2000,
  SESSION_TIMEOUT: 30 * 60 * 1000, // 30 minutos
  BATCH_DELAY: 5000, // 5 segundos para batch de eventos
  STORAGE_PREFIX: 'sempreg-',
  FINGERPRINT_CACHE_DURATION: 24 * 60 * 60 * 1000 // 24 horas
};

// Cache para fingerprint del dispositivo
let fingerprintCache = null;
let fingerprintTimestamp = null;

export const AnalyticsUtils = {
  
  // Sistema de cola para batch de eventos
  eventQueue: [],
  batchTimer: null,
  
  // Verificar si analytics está habilitado con cache
  isAnalyticsEnabled: (() => {
    let cache = null;
    let cacheTime = null;
    
    return () => {
      const now = Date.now();
      if (cache !== null && cacheTime && (now - cacheTime < 1000)) {
        return cache;
      }
      
      cache = hasConsentFor('analytics') || hasConsentFor('all');
      cacheTime = now;
      return cache;
    };
  })(),

  // Generar fingerprint único del dispositivo
  generateDeviceFingerprint: async () => {
    if (typeof window === 'undefined') return 'server';
    
    // Verificar cache
    const now = Date.now();
    if (fingerprintCache && fingerprintTimestamp && 
        (now - fingerprintTimestamp < CONFIG.FINGERPRINT_CACHE_DURATION)) {
      return fingerprintCache;
    }
    
    try {
      const components = [
        navigator.userAgent,
        navigator.language,
        navigator.platform,
        navigator.hardwareConcurrency || 'unknown',
        screen.width + 'x' + screen.height,
        screen.colorDepth,
        new Date().getTimezoneOffset(),
        !!window.sessionStorage,
        !!window.localStorage,
        !!window.indexedDB,
        // Canvas fingerprinting (simple version)
        await getCanvasFingerprint()
      ];
      
      const fingerprint = await hashString(components.join('|'));
      
      // Guardar en cache
      fingerprintCache = fingerprint;
      fingerprintTimestamp = now;
      
      return fingerprint;
    } catch (error) {
      console.warn('Error generating fingerprint:', error);
      return generateSimpleId();
    }
  },

  // Tracking de eventos con sistema de cola
  trackEvent: async (eventName, eventData = {}) => {
    if (!AnalyticsUtils.isAnalyticsEnabled()) return;
    
    try {
      const event = {
        id: generateEventId(),
        name: eventName,
        data: sanitizeEventData(eventData),
        timestamp: new Date().toISOString(),
        url: typeof window !== 'undefined' ? window.location.href : '',
        userAgent: typeof navigator !== 'undefined' ? navigator.userAgent : '',
        sessionId: await getOrCreateSessionId(),
        deviceId: await AnalyticsUtils.generateDeviceFingerprint(),
        performance: getPagePerformanceMetrics()
      };

      // Agregar a la cola
      AnalyticsUtils.eventQueue.push(event);
      
      // Guardar en localStorage inmediatamente
      saveEventToStorage(event);
      
      // Programar envío batch
      if (!AnalyticsUtils.batchTimer) {
        AnalyticsUtils.batchTimer = setTimeout(() => {
          AnalyticsUtils.flushEventQueue();
        }, CONFIG.BATCH_DELAY);
      }
      
      return event.id;
    } catch (error) {
      console.error('Error tracking event:', error);
      return null;
    }
  },

  // Enviar eventos en batch
  flushEventQueue: async () => {
    if (AnalyticsUtils.eventQueue.length === 0) return;
    
    const events = [...AnalyticsUtils.eventQueue];
    AnalyticsUtils.eventQueue = [];
    AnalyticsUtils.batchTimer = null;
    
    try {
      const { apiRequest, API_CONFIG } = await import('@/config/api');
      
      // Enviar en batch
      const response = await apiRequest(API_CONFIG.ENDPOINTS.EVENTS_BATCH, {
        method: 'POST',
        body: JSON.stringify({ 
          events,
          metadata: {
            batchId: generateBatchId(),
            timestamp: new Date().toISOString()
          }
        })
      });
      
      // Si el envío fue exitoso, limpiar eventos enviados del storage
      if (response.ok) {
        cleanupSentEvents(events);
      }
    } catch (error) {
      // Si falla, volver a agregar a la cola para retry
      AnalyticsUtils.eventQueue.unshift(...events);
      console.warn('Failed to send events batch, will retry:', error);
    }
  },

  // Tracking de página mejorado con deduplicación
  trackPageView: async (page, additionalData = {}) => {
    if (!AnalyticsUtils.isAnalyticsEnabled()) return;
    
    const sessionId = await getOrCreateSessionId();
    const pageViewId = generatePageViewId(page, sessionId);
    
    // Verificar si ya se registró esta vista
    if (isDuplicatePageView(pageViewId)) {
            return;
    }
    
    const pageViewData = {
      page,
      title: document.title,
      referrer: getReferrerInfo(),
      viewport: getViewportInfo(),
      connection: getConnectionInfo(),
      ...additionalData
    };
    
    // Registrar la vista
    markPageViewAsTracked(pageViewId);
    
    return AnalyticsUtils.trackEvent('page_view', pageViewData);
  },

  // Métricas de rendimiento extendidas
  getPerformanceMetrics: () => {
    if (!window.performance) return null;
    
    const navigation = performance.getEntriesByType('navigation')[0];
    const paint = performance.getEntriesByType('paint');
    
    if (!navigation) return null;

    const metrics = {
      // Métricas básicas
      loadTime: navigation.loadEventEnd - navigation.loadEventStart,
      domContentLoaded: navigation.domContentLoadedEventEnd - navigation.domContentLoadedEventStart,
      timeToFirstByte: navigation.responseStart - navigation.requestStart,
      totalTime: navigation.loadEventEnd - navigation.fetchStart,
      
      // Métricas adicionales
      dnsLookup: navigation.domainLookupEnd - navigation.domainLookupStart,
      tcpConnection: navigation.connectEnd - navigation.connectStart,
      requestTime: navigation.responseEnd - navigation.requestStart,
      domProcessing: navigation.domComplete - navigation.domInteractive,
      
      // Core Web Vitals
      firstPaint: paint.find(p => p.name === 'first-paint')?.startTime || 0,
      firstContentfulPaint: paint.find(p => p.name === 'first-contentful-paint')?.startTime || 0,
      
      // Recursos
      resourceCount: performance.getEntriesByType('resource').length,
      transferSize: navigation.transferSize || 0,
      encodedBodySize: navigation.encodedBodySize || 0
    };

    // Agregar LCP, FID, CLS si están disponibles
    if (window.PerformanceObserver) {
      try {
        const observer = new PerformanceObserver((list) => {
          for (const entry of list.getEntries()) {
            if (entry.entryType === 'largest-contentful-paint') {
              metrics.largestContentfulPaint = entry.renderTime || entry.loadTime;
            }
          }
        });
        observer.observe({ entryTypes: ['largest-contentful-paint'] });
      } catch (e) {
        // PerformanceObserver no soportado completamente
      }
    }

    return metrics;
  },

  // Sistema de sesiones mejorado
  getSessionInfo: async () => {
    const sessionId = await getOrCreateSessionId();
    const sessionData = JSON.parse(sessionStorage.getItem(`${CONFIG.STORAGE_PREFIX}session`) || '{}');
    
    return {
      id: sessionId,
      startTime: sessionData.startTime,
      duration: Date.now() - new Date(sessionData.startTime).getTime(),
      pageCount: sessionData.pageCount || 0,
      eventCount: sessionData.eventCount || 0,
      isNew: sessionData.isNew || false
    };
  },

  // Exportar datos con compresión opcional
  exportAllData: async (options = {}) => {
    const { compress = false, format = 'json' } = options;
    
    const data = {
      visits: getStoredVisits(),
      events: getStoredEvents(),
      sessions: await AnalyticsUtils.getSessionInfo(),
      performance: AnalyticsUtils.getPerformanceMetrics(),
      deviceInfo: await getDeviceInfo(),
      cookieConsent: getCookieConsent(),
      exportMetadata: {
        timestamp: new Date().toISOString(),
        version: '2.0',
        compressed: compress
      }
    };

    let exportData = JSON.stringify(data, null, 2);
    
    // Comprimir si se solicita
    if (compress && typeof CompressionStream !== 'undefined') {
      const blob = new Blob([exportData]);
      const stream = blob.stream().pipeThrough(new CompressionStream('gzip'));
      const compressedBlob = await new Response(stream).blob();
      downloadBlob(compressedBlob, `analytics-${Date.now()}.json.gz`, 'application/gzip');
    } else {
      const blob = new Blob([exportData], { type: 'application/json' });
      downloadBlob(blob, `analytics-${Date.now()}.json`, 'application/json');
    }
  },

  // Limpiar datos con confirmación mejorada
  clearAllData: async (options = {}) => {
    const { keepConsent = true, keepDeviceId = true } = options;
    
    const message = `¿Estás seguro de que quieres eliminar todos los datos de analytics?
    ${keepConsent ? '\n• Se mantendrán las preferencias de cookies' : ''}
    ${keepDeviceId ? '\n• Se mantendrá el ID del dispositivo' : ''}`;
    
    if (!confirm(message)) return false;
    
    // Flush pending events before clearing
    await AnalyticsUtils.flushEventQueue();
    
    const keysToRemove = [
      'visits', 'events', 'page-views', 'sessions', 
      'visit-count', 'current-visit'
    ];
    
    if (!keepConsent) keysToRemove.push('cookie-consent', 'cookie-settings');
    if (!keepDeviceId) keysToRemove.push('device-id');
    
    keysToRemove.forEach(key => {
      localStorage.removeItem(`${CONFIG.STORAGE_PREFIX}${key}`);
    });
    
    sessionStorage.clear();
    
    return true;
  },

  // Análisis avanzado
  getAdvancedSummary: async () => {
    const visits = getStoredVisits();
    const events = getStoredEvents();
    const sessions = await getSessionAnalysis();
    
    return {
      // Métricas básicas
      totalVisits: visits.length,
      totalEvents: events.length,
      uniqueSessions: sessions.unique,
      
      // Análisis temporal
      visitsBy: {
        hour: getVisitsByHour(visits),
        dayOfWeek: getVisitsByDayOfWeek(visits),
        date: getVisitsByDate(visits, 30) // últimos 30 días
      },
      
      // Análisis de comportamiento
      behavior: {
        avgSessionDuration: sessions.avgDuration,
        pagesPerSession: sessions.avgPages,
        bounceRate: calculateBounceRate(sessions.data),
        returnVisitorRate: calculateReturnRate(visits)
      },
      
      // Top datos
      top: {
        pages: getTopPages(visits, 10),
        events: getTopEvents(events, 10),
        referrers: getTopReferrers(visits, 5),
        devices: getDeviceStats(visits)
      },
      
      // Tendencias
      trends: {
        growth: calculateGrowthRate(visits),
        peakHours: identifyPeakHours(visits),
        userFlow: analyzeUserFlow(visits)
      }
    };
  }
};

// === Funciones auxiliares ===

// Generar hash para fingerprinting
async function hashString(str) {
  if (crypto.subtle) {
    const msgBuffer = new TextEncoder().encode(str);
    const hashBuffer = await crypto.subtle.digest('SHA-256', msgBuffer);
    const hashArray = Array.from(new Uint8Array(hashBuffer));
    return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
  }
  // Fallback para navegadores sin crypto.subtle
  return simpleHash(str);
}

// Hash simple como fallback
function simpleHash(str) {
  let hash = 0;
  for (let i = 0; i < str.length; i++) {
    const char = str.charCodeAt(i);
    hash = ((hash << 5) - hash) + char;
    hash = hash & hash;
  }
  return Math.abs(hash).toString(36);
}

// Canvas fingerprinting
async function getCanvasFingerprint() {
  try {
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');
    ctx.textBaseline = 'top';
    ctx.font = '14px Arial';
    ctx.textBaseline = 'alphabetic';
    ctx.fillStyle = '#f60';
    ctx.fillRect(125, 1, 62, 20);
    ctx.fillStyle = '#069';
    ctx.fillText('Canvas fingerprint', 2, 15);
    ctx.fillStyle = 'rgba(102, 204, 0, 0.7)';
    ctx.fillText('Canvas fingerprint', 4, 17);
    return canvas.toDataURL();
  } catch {
    return 'canvas-not-available';
  }
}

// Gestión de sesiones mejorada
async function getOrCreateSessionId() {
  if (typeof window === 'undefined') return 'server-session';
  
  let sessionData = JSON.parse(sessionStorage.getItem(`${CONFIG.STORAGE_PREFIX}session`) || 'null');
  const now = Date.now();
  
  // Verificar si la sesión expiró
  if (sessionData && sessionData.lastActivity) {
    const timeSinceActivity = now - sessionData.lastActivity;
    if (timeSinceActivity > CONFIG.SESSION_TIMEOUT) {
      sessionData = null; // Sesión expirada
    }
  }
  
  // Crear nueva sesión si es necesario
  if (!sessionData) {
    const deviceId = await AnalyticsUtils.generateDeviceFingerprint();
    sessionData = {
      id: `${deviceId}_${now}_${Math.random().toString(36).substr(2, 9)}`,
      startTime: new Date().toISOString(),
      lastActivity: now,
      pageCount: 0,
      eventCount: 0,
      isNew: true
    };
  } else {
    sessionData.lastActivity = now;
    sessionData.isNew = false;
  }
  
  sessionStorage.setItem(`${CONFIG.STORAGE_PREFIX}session`, JSON.stringify(sessionData));
  return sessionData.id;
}

// Sanitizar datos de eventos
function sanitizeEventData(data) {
  const sanitized = {};
  const MAX_STRING_LENGTH = 1000;
  const MAX_DEPTH = 5;
  
  function sanitize(obj, depth = 0) {
    if (depth > MAX_DEPTH) return '[Max depth exceeded]';
    
    if (obj === null || obj === undefined) return obj;
    if (typeof obj === 'string') return obj.slice(0, MAX_STRING_LENGTH);
    if (typeof obj === 'number' || typeof obj === 'boolean') return obj;
    if (obj instanceof Date) return obj.toISOString();
    
    if (Array.isArray(obj)) {
      return obj.slice(0, 100).map(item => sanitize(item, depth + 1));
    }
    
    if (typeof obj === 'object') {
      const result = {};
      Object.keys(obj).slice(0, 50).forEach(key => {
        result[key] = sanitize(obj[key], depth + 1);
      });
      return result;
    }
    
    return String(obj).slice(0, MAX_STRING_LENGTH);
  }
  
  return sanitize(data);
}

// Obtener información del referrer
function getReferrerInfo() {
  const referrer = document.referrer;
  if (!referrer) return { type: 'direct', source: null };
  
  try {
    const url = new URL(referrer);
    const currentHost = window.location.hostname;
    
    if (url.hostname === currentHost) {
      return { type: 'internal', source: url.pathname };
    }
    
    // Detectar fuentes conocidas
    const sources = {
      'google': 'Google',
      'facebook': 'Facebook',
      'twitter': 'Twitter',
      'linkedin': 'LinkedIn',
      'instagram': 'Instagram'
    };
    
    for (const [key, name] of Object.entries(sources)) {
      if (url.hostname.includes(key)) {
        return { type: 'social', source: name, url: referrer };
      }
    }
    
    return { type: 'external', source: url.hostname, url: referrer };
  } catch {
    return { type: 'unknown', source: referrer };
  }
}

// Utilidades de almacenamiento
function getStoredVisits() {
  try {
    return JSON.parse(localStorage.getItem(`${CONFIG.STORAGE_PREFIX}visits`) || '[]');
  } catch {
    return [];
  }
}

function getStoredEvents() {
  try {
    return JSON.parse(localStorage.getItem(`${CONFIG.STORAGE_PREFIX}events`) || '[]');
  } catch {
    return [];
  }
}

function saveEventToStorage(event) {
  try {
    const events = getStoredEvents();
    events.push(event);
    
    // Mantener límite de eventos
    if (events.length > CONFIG.MAX_EVENTS) {
      events.splice(0, events.length - CONFIG.MAX_EVENTS);
    }
    
    localStorage.setItem(`${CONFIG.STORAGE_PREFIX}events`, JSON.stringify(events));
  } catch (e) {
    console.warn('Failed to save event to storage:', e);
  }
}

// Funciones de análisis
function calculateBounceRate(sessions) {
  if (!sessions || sessions.length === 0) return 0;
  const bouncedSessions = sessions.filter(s => s.pageCount === 1).length;
  return ((bouncedSessions / sessions.length) * 100).toFixed(1);
}

function calculateReturnRate(visits) {
  const deviceIds = visits.map(v => v.deviceId).filter(Boolean);
  const uniqueDevices = new Set(deviceIds);
  const returnDevices = deviceIds.filter((id, idx) => 
    deviceIds.indexOf(id) !== idx
  );
  
  if (uniqueDevices.size === 0) return 0;
  return ((returnDevices.length / uniqueDevices.size) * 100).toFixed(1);
}

// Helpers adicionales
function generateEventId() {
  return `evt_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}

function generateBatchId() {
  return `batch_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}

function generateSimpleId() {
  return `${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}

function getViewportInfo() {
  return {
    width: window.innerWidth,
    height: window.innerHeight,
    devicePixelRatio: window.devicePixelRatio || 1
  };
}

function getConnectionInfo() {
  const connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;
  if (!connection) return null;
  
  return {
    effectiveType: connection.effectiveType,
    downlink: connection.downlink,
    rtt: connection.rtt,
    saveData: connection.saveData
  };
}

// Exportar funciones compatibles con el hook existente
export const trackEvent = AnalyticsUtils.trackEvent;
export const trackPageView = AnalyticsUtils.trackPageView;
export const getStoredAnalytics = () => ({
  visits: getStoredVisits(),
  events: getStoredEvents(),
  cookieConsent: getCookieConsent()
});

export default AnalyticsUtils;