/**
 * Hook pour gérer l'état et les contrôles du player
 */

import { useEffect, useRef, useCallback } from 'react';
import { usePlayerStore } from '../store/playerStore';
import { audioPlayerService } from '../services/playerService';
import type { PlayerHook, Track } from '../types';
import { logger } from '@/utils/logger';

/**
 * Hook principal pour accéder à l'état et aux contrôles du player
 * Intègre le store et le service audio
 */
export function usePlayer(
  audioElementRef?: React.RefObject<HTMLAudioElement>,
): PlayerHook {
  const store = usePlayerStore();
  const internalAudioRef = useRef<HTMLAudioElement | null>(null);
  const audioRef = audioElementRef?.current || internalAudioRef.current;

  // Initialiser le service audio avec l'élément audio
  useEffect(() => {
    if (!audioRef) return;

    audioPlayerService.initialize(audioRef);

    return () => {
      audioPlayerService.cleanup();
    };
  }, [audioRef]);

  // Synchroniser le volume et le mute avec l'élément audio
  useEffect(() => {
    if (!audioRef) return;

    const volumeValue = store.muted ? 0 : store.volume / 100;
    audioPlayerService.setVolume(volumeValue);
    audioPlayerService.setMuted(store.muted);
  }, [audioRef, store.volume, store.muted]);

  // Charger la track dans l'élément audio quand elle change
  useEffect(() => {
    if (!audioRef) return;

    const loadTrack = async () => {
      try {
        await audioPlayerService.loadTrack(store.currentTrack);
      } catch (error) {
        logger.error('Failed to load track:', { error });
      }
    };

    loadTrack();
  }, [audioRef, store.currentTrack]);

  // Synchroniser l'état de lecture avec l'élément audio
  useEffect(() => {
    if (!audioRef) return;

    const syncPlayback = async () => {
      try {
        if (store.isPlaying) {
          await audioPlayerService.play();
        } else {
          audioPlayerService.pause();
        }
      } catch (error) {
        logger.error('Failed to sync playback:', { error });
        store.pause();
      }
    };

    syncPlayback();
  }, [audioRef, store.isPlaying, store]);

  // Configurer les callbacks d'événements audio
  useEffect(() => {
    if (!audioRef) return;

    // Callback pour les mises à jour de temps
    audioPlayerService.onTimeUpdate((currentTime) => {
      store.setCurrentTime(currentTime);
    });

    // Callback pour les changements de durée
    audioPlayerService.onDurationChange((duration) => {
      store.setDuration(duration);
    });

    // Callback quand la track se termine
    audioPlayerService.onEnded(() => {
      if (store.repeat === 'track') {
        // Répéter la track actuelle
        audioPlayerService.seek(0);
        audioPlayerService
          .play()
          .catch((err) =>
            logger.error('Failed to reply track:', { error: err }),
          );
      } else {
        // Passer à la track suivante
        store.next();
      }
    });

    // Callback pour les erreurs
    audioPlayerService.onError((error) => {
      logger.error('Audio playback error:', { error });
      store.pause();
    });

    // Callback pour le début de lecture
    audioPlayerService.onPlay(() => {
      if (!store.isPlaying) {
        store.resume();
      }
    });

    // Callback pour la pause
    audioPlayerService.onPause(() => {
      if (store.isPlaying) {
        store.pause();
      }
    });

    return () => {
      // Nettoyer les callbacks
      audioPlayerService.onTimeUpdate(null);
      audioPlayerService.onDurationChange(null);
      audioPlayerService.onEnded(null);
      audioPlayerService.onError(null);
      audioPlayerService.onPlay(null);
      audioPlayerService.onPause(null);
    };
  }, [audioRef, store]);

  // Wrapper pour play qui charge la track dans le service
  const handlePlay = useCallback(
    async (track?: Track) => {
      store.play(track);
      if (track && audioRef) {
        try {
          await audioPlayerService.loadTrack(track);
          await audioPlayerService.play();
        } catch (error) {
          logger.error('Failed to play track:', { error });
          store.pause();
        }
      }
    },
    [store, audioRef],
  );

  // Wrapper pour pause
  const handlePause = useCallback(() => {
    store.pause();
    if (audioRef) {
      audioPlayerService.pause();
    }
  }, [store, audioRef]);

  // Wrapper pour resume
  const handleResume = useCallback(async () => {
    store.resume();
    if (audioRef) {
      try {
        await audioPlayerService.play();
      } catch (error) {
        logger.error('Failed to resume playback:', { error });
        store.pause();
      }
    }
  }, [store, audioRef]);

  // Wrapper pour stop
  const handleStop = useCallback(() => {
    store.stop();
    if (audioRef) {
      audioPlayerService.stop();
    }
  }, [store, audioRef]);

  // Wrapper pour seek
  const handleSeek = useCallback(
    (time: number) => {
      store.seek(time);
      if (audioRef) {
        audioPlayerService.seek(time);
      }
    },
    [store, audioRef],
  );

  // Wrapper pour setVolume
  const handleSetVolume = useCallback(
    (volume: number) => {
      store.setVolume(volume);
      if (audioRef) {
        const volumeValue = store.muted ? 0 : volume / 100;
        audioPlayerService.setVolume(volumeValue);
      }
    },
    [store, audioRef],
  );

  // Wrapper pour toggleMute
  const handleToggleMute = useCallback(() => {
    store.toggleMute();
    if (audioRef) {
      audioPlayerService.setMuted(!store.muted);
    }
  }, [store, audioRef]);

  return {
    // State
    currentTrack: store.currentTrack,
    isPlaying: store.isPlaying,
    currentTime: store.currentTime,
    duration: store.duration,
    volume: store.volume,
    muted: store.muted,
    queue: store.queue,
    currentIndex: store.currentIndex,
    repeat: store.repeat,
    shuffle: store.shuffle,

    // Controls
    play: handlePlay,
    pause: handlePause,
    resume: handleResume,
    stop: handleStop,
    next: store.next,
    previous: store.previous,
    seek: handleSeek,
    setVolume: handleSetVolume,
    toggleMute: handleToggleMute,
    toggleShuffle: store.toggleShuffle,
    setRepeat: store.setRepeat,
    addToQueue: store.addToQueue,
    clearQueue: store.clearQueue,
  };
}
