/**
 * Service de monitoring avancé côté client
 */

export interface PerformanceMetric {
  name: string;
  value: number;
  timestamp: number;
  tags?: Record<string, string>;
}

export interface ErrorMetric {
  error: string;
  stack?: string;
  url: string;
  userAgent: string;
  timestamp: number;
  userId?: string;
}

export interface UserAction {
  action: string;
  component: string;
  timestamp: number;
  duration?: number;
  metadata?: Record<string, any>;
}

export class MonitoringService {
  private static metrics: PerformanceMetric[] = [];
  private static errors: ErrorMetric[] = [];
  private static userActions: UserAction[] = [];
  private static isEnabled = true;

  /**
   * Initialise le service de monitoring
   */
  static init(): void {
    if (typeof window === 'undefined') return;

    // Monitoring des erreurs JavaScript
    window.addEventListener('error', (event) => {
      this.recordError({
        error: event.message,
        stack: event.error?.stack,
        url: window.location.href,
        userAgent: navigator.userAgent,
        timestamp: Date.now()
      });
    });

    // Monitoring des promesses rejetées
    window.addEventListener('unhandledrejection', (event) => {
      this.recordError({
        error: `Unhandled Promise Rejection: ${event.reason}`,
        url: window.location.href,
        userAgent: navigator.userAgent,
        timestamp: Date.now()
      });
    });

    // Monitoring des performances de navigation
    if ('performance' in window) {
      window.addEventListener('load', () => {
        setTimeout(() => {
          this.recordNavigationMetrics();
        }, 0);
      });
    }

    // Envoi périodique des métriques
    setInterval(() => {
      this.sendMetrics();
    }, 60000); // Toutes les minutes
  }

  /**
   * Enregistre une métrique de performance
   */
  static recordMetric(name: string, value: number, tags?: Record<string, string>): void {
    if (!this.isEnabled) return;

    this.metrics.push({
      name,
      value,
      timestamp: Date.now(),
      tags
    });

    // Limiter le nombre de métriques en mémoire
    if (this.metrics.length > 1000) {
      this.metrics = this.metrics.slice(-500);
    }
  }

  /**
   * Enregistre une erreur
   */
  static recordError(error: ErrorMetric): void {
    if (!this.isEnabled) return;

    this.errors.push(error);

    // Limiter le nombre d'erreurs en mémoire
    if (this.errors.length > 100) {
      this.errors = this.errors.slice(-50);
    }
  }

  /**
   * Enregistre une action utilisateur
   */
  static recordUserAction(action: string, component: string, metadata?: Record<string, any>): void {
    if (!this.isEnabled) return;

    this.userActions.push({
      action,
      component,
      timestamp: Date.now(),
      metadata
    });

    // Limiter le nombre d'actions en mémoire
    if (this.userActions.length > 500) {
      this.userActions = this.userActions.slice(-250);
    }
  }

  /**
   * Mesure le temps d'exécution d'une fonction
   */
  static async measureTime<T>(
    name: string,
    fn: () => Promise<T>,
    tags?: Record<string, string>
  ): Promise<T> {
    const start = performance.now();
    try {
      const result = await fn();
      const duration = performance.now() - start;
      this.recordMetric(`${name}.duration`, duration, tags);
      this.recordMetric(`${name}.success`, 1, tags);
      return result;
    } catch (error) {
      const duration = performance.now() - start;
      this.recordMetric(`${name}.duration`, duration, tags);
      this.recordMetric(`${name}.error`, 1, tags);
      throw error;
    }
  }

  /**
   * Enregistre les métriques de navigation
   */
  private static recordNavigationMetrics(): void {
    if (!('performance' in window) || !window.performance.timing) return;

    const timing = window.performance.timing;
    const navigation = window.performance.navigation;

    // Temps de chargement de la page
    const pageLoadTime = timing.loadEventEnd - timing.navigationStart;
    this.recordMetric('page.load_time', pageLoadTime, {
      url: window.location.pathname
    });

    // Temps de réponse du serveur
    const serverResponseTime = timing.responseEnd - timing.requestStart;
    this.recordMetric('page.server_response_time', serverResponseTime);

    // Temps de rendu DOM
    const domRenderTime = timing.domContentLoadedEventEnd - timing.domLoading;
    this.recordMetric('page.dom_render_time', domRenderTime);

    // Type de navigation
    const navigationType = navigation.type === 0 ? 'navigate' : 
                          navigation.type === 1 ? 'reload' : 
                          navigation.type === 2 ? 'back_forward' : 'unknown';
    this.recordMetric('page.navigation_type', 1, {
      type: navigationType
    });
  }

  /**
   * Envoie les métriques au serveur
   */
  private static async sendMetrics(): Promise<void> {
    if (this.metrics.length === 0 && this.errors.length === 0 && this.userActions.length === 0) {
      return;
    }

    try {
      const payload = {
        metrics: [...this.metrics],
        errors: [...this.errors],
        userActions: [...this.userActions],
        timestamp: Date.now(),
        url: window.location.href,
        userAgent: navigator.userAgent
      };

      // Envoyer au serveur (endpoint à implémenter)
      await fetch('/api/monitoring', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify(payload)
      });

      // Vider les buffers après envoi réussi
      this.metrics = [];
      this.errors = [];
      this.userActions = [];

    } catch (error) {
      console.warn('Échec de l\'envoi des métriques:', error);
    }
  }

  /**
   * Obtient les statistiques actuelles
   */
  static getStats(): {
    metricsCount: number;
    errorsCount: number;
    userActionsCount: number;
    isEnabled: boolean;
  } {
    return {
      metricsCount: this.metrics.length,
      errorsCount: this.errors.length,
      userActionsCount: this.userActions.length,
      isEnabled: this.isEnabled
    };
  }

  /**
   * Active ou désactive le monitoring
   */
  static setEnabled(enabled: boolean): void {
    this.isEnabled = enabled;
  }

  /**
   * Vide tous les buffers
   */
  static clear(): void {
    this.metrics = [];
    this.errors = [];
    this.userActions = [];
  }
}

// Initialisation automatique
if (typeof window !== 'undefined') {
  MonitoringService.init();
}

// Hook React pour le monitoring des composants
export function useMonitoring(componentName: string) {
  const recordAction = (action: string, metadata?: Record<string, any>) => {
    MonitoringService.recordUserAction(action, componentName, metadata);
  };

  const measureAsync = async <T>(
    name: string,
    fn: () => Promise<T>
  ): Promise<T> => {
    return MonitoringService.measureTime(`${componentName}.${name}`, fn);
  };

  return {
    recordAction,
    measureAsync
  };
}
