/**
 * TabataFit Music Player Hook
 * Manages background music playback synced with workout timer
 * Loads tracks from Supabase Storage based on workout's musicVibe
 */

import { logger } from '../utils/logger'

import { useRef, useEffect, useCallback, useState } from 'react'
import { Audio, type AVPlaybackStatus } from 'expo-av'
import { useUserStore } from '../stores'
import { musicService, type MusicTrack } from '../services/music'
import type { MusicVibe } from '../types'

interface UseMusicPlayerOptions {
  vibe: MusicVibe
  isPlaying: boolean
  volume?: number
}

interface UseMusicPlayerReturn {
  /** Current track being played */
  currentTrack: MusicTrack | null
  /** Whether music is loaded and ready */
  isReady: boolean
  /** Error message if loading failed */
  error: string | null
  /** Set volume (0-1) */
  setVolume: (volume: number) => void
  /** Skip to next track */
  nextTrack: () => void
}

export function useMusicPlayer(options: UseMusicPlayerOptions): UseMusicPlayerReturn {
  const { vibe, isPlaying, volume = 0.5 } = options
  
  const musicEnabled = useUserStore((s) => s.settings.musicEnabled)
  const soundRef = useRef<Audio.Sound | null>(null)
  const tracksRef = useRef<MusicTrack[]>([])
  const currentTrackIndexRef = useRef(0)
  
  const [currentTrack, setCurrentTrack] = useState<MusicTrack | null>(null)
  const [isReady, setIsReady] = useState(false)
  const [error, setError] = useState<string | null>(null)

  // Configure audio session for background music
  useEffect(() => {
    Audio.setAudioModeAsync({
      playsInSilentModeIOS: true,
      staysActiveInBackground: true,
      shouldDuckAndroid: true,
      // Mix with other audio (allows sound effects to play over music)
      interruptionModeIOS: 1, // INTERRUPTION_MODE_IOS_MIX_WITH_OTHERS
      interruptionModeAndroid: 1, // INTERRUPTION_MODE_ANDROID_DUCK_OTHERS
    })

    return () => {
      // Cleanup on unmount
      if (soundRef.current) {
        soundRef.current.unloadAsync().catch(() => {})
        soundRef.current = null
      }
    }
  }, [])

  // Load tracks when vibe changes
  useEffect(() => {
    let isMounted = true

    async function loadTracks() {
      try {
        setIsReady(false)
        setError(null)

        // Unload current track if any
        if (soundRef.current) {
          await soundRef.current.unloadAsync()
          soundRef.current = null
        }

        const tracks = await musicService.loadTracksForVibe(vibe)
        
        if (!isMounted) return

        tracksRef.current = tracks
        
        if (tracks.length > 0) {
          // Select random starting track
          currentTrackIndexRef.current = Math.floor(Math.random() * tracks.length)
          const track = tracks[currentTrackIndexRef.current]
          setCurrentTrack(track)
          await loadAndPlayTrack(track, false)
        } else {
          setError('No tracks available')
        }

        setIsReady(true)
      } catch (err) {
        if (!isMounted) return
        setError(err instanceof Error ? err.message : 'Failed to load music')
        setIsReady(false)
      }
    }

    if (musicEnabled) {
      loadTracks()
    }

    return () => {
      isMounted = false
    }
  }, [vibe, musicEnabled])

  // Load and prepare a track
  const loadAndPlayTrack = useCallback(async (track: MusicTrack, autoPlay: boolean = true) => {
    try {
      if (soundRef.current) {
        await soundRef.current.unloadAsync()
      }

      // For mock tracks without URLs, skip loading
      if (!track.url) {
        logger.log(`[MusicPlayer] Mock track: ${track.title} - ${track.artist}`)
        return
      }

      const { sound } = await Audio.Sound.createAsync(
        { uri: track.url },
        {
          shouldPlay: autoPlay && isPlaying && musicEnabled,
          volume: volume,
          isLooping: false,
          positionMillis: 10_000,
        },
        onPlaybackStatusUpdate
      )

      soundRef.current = sound
    } catch (err) {
      logger.error('[MusicPlayer] Error loading track:', err)
    }
  }, [isPlaying, musicEnabled, volume])

  // Handle playback status updates
  const onPlaybackStatusUpdate = useCallback((status: AVPlaybackStatus) => {
    if (!status.isLoaded) return

    // Track finished playing - load next
    if (status.didJustFinish) {
      playNextTrack()
    }
  }, [])

  // Play next track
  const playNextTrack = useCallback(async () => {
    if (tracksRef.current.length === 0) return

    currentTrackIndexRef.current = (currentTrackIndexRef.current + 1) % tracksRef.current.length
    const nextTrack = tracksRef.current[currentTrackIndexRef.current]
    
    setCurrentTrack(nextTrack)
    await loadAndPlayTrack(nextTrack, isPlaying && musicEnabled)
  }, [isPlaying, musicEnabled, loadAndPlayTrack])

  // Handle play/pause based on workout state
  useEffect(() => {
    async function updatePlayback() {
      if (!soundRef.current || !musicEnabled) return

      try {
        const status = await soundRef.current.getStatusAsync()
        if (!status.isLoaded) return

        if (isPlaying && !status.isPlaying) {
          await soundRef.current.playAsync()
        } else if (!isPlaying && status.isPlaying) {
          await soundRef.current.pauseAsync()
        }
      } catch (err) {
        logger.error('[MusicPlayer] Error updating playback:', err)
      }
    }

    updatePlayback()
  }, [isPlaying, musicEnabled])

  // Update volume when it changes
  useEffect(() => {
    async function updateVolume() {
      if (!soundRef.current) return

      try {
        const status = await soundRef.current.getStatusAsync()
        if (status.isLoaded) {
          await soundRef.current.setVolumeAsync(volume)
        }
      } catch (err) {
        logger.error('[MusicPlayer] Error updating volume:', err)
      }
    }

    updateVolume()
  }, [volume])

  // Update music enabled setting
  useEffect(() => {
    async function handleMusicToggle() {
      if (!soundRef.current) return

      try {
        if (!musicEnabled) {
          await soundRef.current.pauseAsync()
        } else if (isPlaying) {
          await soundRef.current.playAsync()
        }
      } catch (err) {
        logger.error('[MusicPlayer] Error toggling music:', err)
      }
    }

    handleMusicToggle()
  }, [musicEnabled, isPlaying])

  // Set volume function
  const setVolume = useCallback((newVolume: number) => {
    const clampedVolume = Math.max(0, Math.min(1, newVolume))
    // Volume is controlled via the store or parent component
    // This function can be used to update the store
  }, [])

  // Next track function
  const nextTrack = useCallback(async () => {
    await playNextTrack()
  }, [playNextTrack])

  return {
    currentTrack,
    isReady,
    error,
    setVolume,
    nextTrack,
  }
}
