import { useRef, useCallback, useEffect, useState } from 'react';
import {
  recordPlaybackEvent,
  PlaybackEvent,
} from '../services/playbackAnalyticsService';
import { logger } from '@/utils/logger';

/**
 * Hook pour tracker les analytics de lecture
 * T0360: Create Playback Analytics Frontend Hook
 *
 * @param trackId - ID du track
 * @param trackDuration - Durée totale du track en secondes (pour calculer completion_rate)
 * @param sendInterval - Intervalle d'envoi automatique en millisecondes (défaut: 30000 = 30s)
 * @returns Fonctions et état pour tracker les événements de lecture
 */
export function usePlaybackAnalytics(
  trackId: string,
  trackDuration: number = 0,
  sendInterval: number = 30000,
) {
  const [loading, setLoading] = useState<boolean>(false);
  const [error, setError] = useState<Error | null>(null);
  const [isPlaying, setIsPlaying] = useState<boolean>(false);
  const [playTime, setPlayTime] = useState<number>(0);
  const [pauseCount, setPauseCount] = useState<number>(0);
  const [seekCount, setSeekCount] = useState<number>(0);

  // Référence pour stocker les analytics (pour l'envoi au backend)
  const analytics = useRef<PlaybackEvent>({
    play_time: 0,
    pause_count: 0,
    seek_count: 0,
    started_at: new Date().toISOString(),
  });

  // Référence pour le timer d'envoi périodique
  const sendIntervalRef = useRef<NodeJS.Timeout | null>(null);

  // Référence pour le timer de tracking du temps de lecture
  const playTimeIntervalRef = useRef<NodeJS.Timeout | null>(null);

  // Référence pour éviter les mises à jour d'état si le composant est démonté
  const cancelledRef = useRef(false);

  // Nettoyer les timers au démontage
  useEffect(() => {
    return () => {
      cancelledRef.current = true;
      if (sendIntervalRef.current) {
        clearInterval(sendIntervalRef.current);
      }
      if (playTimeIntervalRef.current) {
        clearInterval(playTimeIntervalRef.current);
      }
    };
  }, []);

  /**
   * Calcule le taux de complétion
   */
  const calculateCompletionRate = useCallback(
    (playTime: number, duration: number): number => {
      if (duration <= 0) {
        return 0;
      }
      const rate = (playTime / duration) * 100;
      return Math.min(rate, 100); // Limiter à 100%
    },
    [],
  );

  /**
   * Envoie les analytics au backend
   * T0385: Create Playback Analytics Error Handling - Amélioré avec retry et fallback
   */
  const sendAnalytics = useCallback(
    async (final: boolean = false) => {
      if (cancelledRef.current) {
        return;
      }

      try {
        setLoading(true);
        setError(null);

        // Préparer l'événement avec le taux de complétion
        // Synchroniser les valeurs de state avec la ref avant l'envoi
        analytics.current.play_time = playTime;
        analytics.current.pause_count = pauseCount;
        analytics.current.seek_count = seekCount;

        const event: PlaybackEvent = {
          ...analytics.current,
          completion_rate:
            trackDuration > 0
              ? calculateCompletionRate(playTime, trackDuration)
              : undefined,
          ended_at: final
            ? new Date().toISOString()
            : analytics.current.ended_at,
        };

        // T0385: Utiliser recordPlaybackEvent avec retry et fallback automatiques
        await recordPlaybackEvent(trackId, event, {
          onError: (error) => {
            if (!cancelledRef.current) {
              setError(error);
              logger.error('[PlaybackAnalytics] Failed to record analytics:', {
                error,
              });
            }
          },
          onRetry: (attempt, error) => {
            logger.warn(
              `[PlaybackAnalytics] Retrying analytics (attempt ${attempt}):`,
              { error },
            );
          },
        });

        if (!cancelledRef.current) {
          setError(null);
        }
      } catch (err) {
        if (!cancelledRef.current) {
          const error =
            err instanceof Error
              ? err
              : new Error('Failed to record playback analytics');
          setError(error);
          logger.error(
            '[PlaybackAnalytics] Failed to record playback analytics after all retries:',
            { error },
          );
        }
      } finally {
        if (!cancelledRef.current) {
          setLoading(false);
        }
      }
    },
    [
      trackId,
      trackDuration,
      playTime,
      pauseCount,
      seekCount,
      calculateCompletionRate,
    ],
  );

  /**
   * Démarre le tracking du temps de lecture
   */
  const startPlayTimeTracking = useCallback(() => {
    if (playTimeIntervalRef.current) {
      clearInterval(playTimeIntervalRef.current);
    }

    playTimeIntervalRef.current = setInterval(() => {
      if (isPlaying && !cancelledRef.current) {
        setPlayTime((prev) => {
          const newTime = prev + 1;
          analytics.current.play_time = newTime;
          return newTime;
        });
      }
    }, 1000); // Mettre à jour chaque seconde
  }, [isPlaying]);

  /**
   * Arrête le tracking du temps de lecture
   */
  const stopPlayTimeTracking = useCallback(() => {
    if (playTimeIntervalRef.current) {
      clearInterval(playTimeIntervalRef.current);
      playTimeIntervalRef.current = null;
    }
  }, []);

  /**
   * Démarre l'envoi périodique des analytics
   */
  const startPeriodicSending = useCallback(() => {
    if (sendIntervalRef.current) {
      clearInterval(sendIntervalRef.current);
    }

    sendIntervalRef.current = setInterval(() => {
      if (!cancelledRef.current) {
        sendAnalytics(false);
      }
    }, sendInterval);
  }, [sendInterval, sendAnalytics]);

  /**
   * Arrête l'envoi périodique des analytics
   */
  const stopPeriodicSending = useCallback(() => {
    if (sendIntervalRef.current) {
      clearInterval(sendIntervalRef.current);
      sendIntervalRef.current = null;
    }
  }, []);

  /**
   * Track un événement de lecture (play)
   */
  const trackPlay = useCallback(() => {
    if (!isPlaying) {
      setIsPlaying(true);
      startPlayTimeTracking();
      startPeriodicSending();
    }
  }, [isPlaying, startPlayTimeTracking, startPeriodicSending]);

  /**
   * Track un événement de pause
   */
  const trackPause = useCallback(() => {
    if (isPlaying) {
      setIsPlaying(false);
      setPauseCount((prev) => {
        const newCount = prev + 1;
        analytics.current.pause_count = newCount;
        return newCount;
      });
      stopPlayTimeTracking();
    }
  }, [isPlaying, stopPlayTimeTracking]);

  /**
   * Track un événement de seek (saut)
   */
  const trackSeek = useCallback(() => {
    setSeekCount((prev) => {
      const newCount = prev + 1;
      analytics.current.seek_count = newCount;
      return newCount;
    });
  }, []);

  /**
   * Met à jour le temps de lecture manuellement
   */
  const updatePlayTime = useCallback((newPlayTime: number) => {
    const time = Math.max(0, newPlayTime);
    setPlayTime(time);
    analytics.current.play_time = time;
  }, []);

  /**
   * Réinitialise les analytics
   */
  const reset = useCallback(() => {
    setPlayTime(0);
    setPauseCount(0);
    setSeekCount(0);
    analytics.current = {
      play_time: 0,
      pause_count: 0,
      seek_count: 0,
      started_at: new Date().toISOString(),
    };
    setIsPlaying(false);
    stopPlayTimeTracking();
    stopPeriodicSending();
  }, [stopPlayTimeTracking, stopPeriodicSending]);

  /**
   * Envoie les analytics finaux et réinitialise
   */
  const finalize = useCallback(async () => {
    setIsPlaying(false);
    stopPlayTimeTracking();
    stopPeriodicSending();
    analytics.current.ended_at = new Date().toISOString();
    await sendAnalytics(true);
    reset();
  }, [sendAnalytics, stopPlayTimeTracking, stopPeriodicSending, reset]);

  /**
   * Réinitialise l'état d'erreur
   */
  const clearError = useCallback(() => {
    setError(null);
  }, []);

  return {
    // État
    loading,
    error,
    playTime,
    pauseCount,
    seekCount,
    isPlaying,

    // Fonctions de tracking
    trackPlay,
    trackPause,
    trackSeek,
    updatePlayTime,

    // Fonctions de gestion
    sendAnalytics,
    reset,
    finalize,
    clearError,
  };
}
