/**
 * FIX #18, #19, #20, #22, #25: Logger structuré pour le frontend
 * - Support de la corrélation avec request_id (FIX #22)
 * - Logs structurés en JSON en production (FIX #25: Standardisé)
 * - Format texte en développement pour lisibilité
 * - Filtrage selon l'environnement (FIX #21, #24)
 * - Contexte global pour corrélation (FIX #19, #22)
 * - Intégration Sentry pour error tracking (FIX #20)
 *
 * FIX #19: Logger structuré complet avec :
 * - Format JSON optionnel ✅
 * - Corrélation avec request_id ✅
 * - Envoi vers endpoint de logging (optionnel - via VITE_LOG_ENDPOINT)
 *
 * FIX #20: Error tracking avec Sentry :
 * - Capture automatique des erreurs React ✅
 * - Enrichissement avec contexte (request_id, user_id) ✅
 * - Intégration avec le logger structuré ✅
 */

interface LogContext {
  request_id?: string;
  user_id?: string;
  component?: string;
  action?: string;
  [key: string]: unknown;
}

interface Logger {
  debug: (message: string, context?: LogContext, ...args: unknown[]) => void;
  info: (message: string, context?: LogContext, ...args: unknown[]) => void;
  warn: (message: string, context?: LogContext, ...args: unknown[]) => void;
  error: (message: string, context?: LogContext, ...args: unknown[]) => void;
}

const isDev = import.meta.env.DEV;
const isProd = import.meta.env.PROD;

// FIX #21, #24: Configuration du niveau de log via variable d'environnement
// FIX #24: Standardiser sur LOG_LEVEL (avec fallback sur VITE_LOG_LEVEL pour compatibilité)
const logLevel = (
  import.meta.env.VITE_LOG_LEVEL ||
  import.meta.env.LOG_LEVEL ||
  (isDev ? 'DEBUG' : 'WARN')
).toUpperCase();

// Contexte global pour la corrélation
let globalContext: LogContext = {};

/**
 * FIX #22: Définir le contexte global (request_id, user_id, etc.)
 */
export function setLogContext(context: LogContext): void {
  globalContext = { ...globalContext, ...context };
}

/**
 * FIX #22: Obtenir le contexte global
 */
export function getLogContext(): LogContext {
  return { ...globalContext };
}

/**
 * FIX #22: Effacer le contexte global
 */
export function clearLogContext(): void {
  globalContext = {};
}

/**
 * FIX #19: Formater un log structuré avec support JSON et corrélation
 */
function formatLog(
  level: string,
  message: string,
  context?: LogContext,
  ...args: unknown[]
): void {
  const logContext = { ...globalContext, ...context };
  const timestamp = new Date().toISOString();

  // FIX #25: Standardiser sur JSON en production pour faciliter l'agrégation
  if (isProd) {
    // En production : JSON structuré (standardisé pour agrégation)
    const logEntry = {
      timestamp,
      level,
      message,
      ...logContext,
      ...(args.length > 0 && { data: args }),
    };
    const jsonLog = JSON.stringify(logEntry);
    console.log(jsonLog);

    // FIX #19: Envoi optionnel vers endpoint de logging (si configuré)
    // Par défaut, utiliser l'endpoint backend si VITE_LOG_ENDPOINT n'est pas défini
    const logEndpoint =
      import.meta.env.VITE_LOG_ENDPOINT ||
      (import.meta.env.VITE_API_URL
        ? `${import.meta.env.VITE_API_URL}/api/v1/logs/frontend`
        : null);

    // Envoyer tous les logs (pas seulement les erreurs) vers le backend pour archivage
    if (logEndpoint) {
      sendLogToEndpoint(logEndpoint, logEntry).catch(() => {
        // Ignorer les erreurs silencieusement pour ne pas bloquer l'application
      });
    }
  } else {
    // En développement : format lisible
    const contextStr =
      Object.keys(logContext).length > 0
        ? ` ${JSON.stringify(logContext)}`
        : '';
    const argsStr =
      args.length > 0 ? ` ${args.map((a) => JSON.stringify(a)).join(' ')}` : '';
    console.log(`[${level}] ${message}${contextStr}${argsStr}`);
  }
}

/**
 * FIX #19: Envoyer un log vers un endpoint de logging (optionnel)
 */
async function sendLogToEndpoint(
  endpoint: string,
  logEntry: Record<string, unknown>,
): Promise<void> {
  try {
    // Utiliser sendBeacon pour un envoi non-bloquant
    if (navigator.sendBeacon) {
      const blob = new Blob([JSON.stringify(logEntry)], {
        type: 'application/json',
      });
      navigator.sendBeacon(endpoint, blob);
    } else {
      // Fallback sur fetch si sendBeacon n'est pas disponible
      await fetch(endpoint, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(logEntry),
        keepalive: true, // Permet l'envoi même après navigation
      });
    }
  } catch (error) {
    // Ignorer silencieusement pour ne pas bloquer l'application
    // Les logs sont déjà affichés dans la console
  }
}

/**
 * FIX #21: Vérifier si un niveau de log doit être affiché
 */
function shouldLog(level: string): boolean {
  const levelOrder = ['DEBUG', 'INFO', 'WARN', 'ERROR'];
  const currentLevelIndex = levelOrder.indexOf(logLevel);
  const messageLevelIndex = levelOrder.indexOf(level);

  // Si le niveau n'est pas trouvé, autoriser par défaut (sécurité)
  if (currentLevelIndex === -1 || messageLevelIndex === -1) {
    return true;
  }

  // Logger si le niveau du message est >= au niveau configuré
  return messageLevelIndex >= currentLevelIndex;
}

/**
 * Logger structuré qui supporte la corrélation
 * FIX #21: Respecte le niveau de log configuré via VITE_LOG_LEVEL
 */
export const logger: Logger = {
  debug: (message: string, context?: LogContext, ...args: unknown[]) => {
    if (shouldLog('DEBUG')) {
      formatLog('DEBUG', message, context, ...args);
    }
  },
  info: (message: string, context?: LogContext, ...args: unknown[]) => {
    if (shouldLog('INFO')) {
      formatLog('INFO', message, context, ...args);
    }
  },
  warn: (message: string, context?: LogContext, ...args: unknown[]) => {
    if (shouldLog('WARN')) {
      formatLog('WARN', message, context, ...args);
    }
  },
  error: (message: string, context?: LogContext, ...args: unknown[]) => {
    if (shouldLog('ERROR')) {
      formatLog('ERROR', message, context, ...args);

      // FIX #20: Envoyer les erreurs à Sentry si disponible
      if (import.meta.env.PROD && import.meta.env.VITE_SENTRY_DSN) {
        try {
          // Import dynamique pour éviter les erreurs si Sentry n'est pas configuré
          import('@sentry/react')
            .then((Sentry) => {
              const logContext = { ...globalContext, ...context };
              const error = new Error(message);
              Sentry.captureException(error, {
                contexts: {
                  application: logContext,
                },
                tags: logContext.request_id
                  ? { request_id: String(logContext.request_id) }
                  : undefined,
                user: logContext.user_id
                  ? { id: String(logContext.user_id) }
                  : undefined,
              });
            })
            .catch(() => {
              // Ignorer silencieusement si Sentry n'est pas disponible
            });
        } catch {
          // Ignorer silencieusement
        }
      }
    }
  },
};

/**
 * Export par défaut pour faciliter l'import
 */
export default logger;
