"use client"

import { createContext, useContext, useState, useCallback, useEffect, useRef, type ReactNode } from "react"
import { offlineStorage } from "@/lib/offline-storage"
import { useAuth } from "@/components/auth-provider"
import { toast } from "sonner"

type RepeatMode = "off" | "all" | "one"

export interface Track {
  id: string
  title: string
  artist: string
  image: string
  duration: number
  audioUrl?: string
  isOffline?: boolean
  cover_url?: string
  album_cover?: string
  artistId?: string
  albumId?: string
  album?: string
}

interface PlayerContextType {
  currentTrack: Track | null
  isPlaying: boolean
  progress: number
  volume: number
  queue: Track[]
  queueIndex: number
  shuffleEnabled: boolean
  repeatMode: RepeatMode
  likedTracks: Set<string>
  downloadedTracks: Set<string>
  recentlyPlayed: Track[]
  sleepTimerMinutes: number | null
  sleepTimerRemaining: number | null
  isPlayerVisible: boolean
  isOfflineMode: boolean
  isLoading: boolean
  playTrack: (track: Track) => void
  playAlbum: (tracks: Track[], startIndex?: number) => void
  togglePlay: () => void
  nextTrack: () => void
  previousTrack: () => void
  seekTo: (position: number) => void
  setVolume: (volume: number) => void
  toggleShuffle: () => void
  setRepeatMode: (mode: RepeatMode) => void
  addToQueue: (track: Track) => void
  removeFromQueue: (index: number) => void
  clearQueue: () => void
  moveInQueue: (fromIndex: number, toIndex: number) => void
  toggleLike: (trackId: string) => void
  isLiked: (trackId: string) => boolean
  toggleDownload: (trackId: string) => void
  isDownloaded: (trackId: string) => boolean
  setSleepTimer: (minutes: number | null) => void
  cancelSleepTimer: () => void
  hidePlayer: () => void
  showPlayer: () => void
  stopPlayback: () => void
  onTrackPlay?: (track: Track) => void
  setOnTrackPlay: (callback: ((track: Track) => void) | undefined) => void
  updateStreamingSettings: (settings: {
    streamingQuality?: "low" | "normal" | "high" | "very_high"
    dataSaver?: boolean
  }) => void
}

const PlayerContext = createContext<PlayerContextType | undefined>(undefined)

async function resolveAudioUrl(
  originalUrl: string,
  trackId?: string,
): Promise<{ url: string; mimeType: string } | null> {
  if (!originalUrl) return null

  if (trackId) {
    console.log(`[v0] [Player] Using streaming API for track ${trackId}`)
    return { url: `/api/stream/${trackId}`, mimeType: "audio/mpeg" }
  }

  // Fallback for non-track audio
  let urlToResolve = originalUrl.trim()
  if (!urlToResolve.startsWith("http://") && !urlToResolve.startsWith("https://") && !urlToResolve.startsWith("/")) {
    if (urlToResolve.includes(".") && urlToResolve.includes("/")) {
      urlToResolve = `https://${urlToResolve}`
    }
  }

  const extension = urlToResolve.split(".").pop()?.toLowerCase()?.split("?")[0]
  const mimeTypes: Record<string, string> = {
    mp3: "audio/mpeg",
    m4a: "audio/mp4",
    aac: "audio/aac",
    ogg: "audio/ogg",
    wav: "audio/wav",
    webm: "audio/webm",
    flac: "audio/flac",
  }
  const mimeType = mimeTypes[extension || "mp3"] || "audio/mpeg"

  return { url: urlToResolve, mimeType }
}

export function PlayerProvider({ children }: { children: ReactNode }) {
  const { user } = useAuth()
  const currentUserId = user?.id || null
  const previousUserIdRef = useRef<string | null>(null)

  const [currentTrack, setCurrentTrack] = useState<Track | null>(null)
  const [isPlaying, setIsPlaying] = useState(false)
  const [isLoading, setIsLoading] = useState(false)
  const [progress, setProgress] = useState(0)
  const [volume, setVolumeState] = useState(80)
  const [queue, setQueue] = useState<Track[]>([])
  const [queueIndex, setQueueIndex] = useState(0)
  const [shuffleEnabled, setShuffleEnabled] = useState(false)
  const [repeatMode, setRepeatModeState] = useState<RepeatMode>("off")
  const [likedTracks, setLikedTracks] = useState<Set<string>>(new Set())
  const [downloadedTracks, setDownloadedTracks] = useState<Set<string>>(new Set())
  const [recentlyPlayed, setRecentlyPlayed] = useState<Track[]>([])
  const [sleepTimerMinutes, setSleepTimerMinutes] = useState<number | null>(null)
  const [sleepTimerRemaining, setSleepTimerRemaining] = useState<number | null>(null)
  const [onTrackPlay, setOnTrackPlayState] = useState<((track: Track) => void) | undefined>(undefined)
  const [isPlayerVisible, setIsPlayerVisible] = useState(true)
  const [isOfflineMode, setIsOfflineMode] = useState(false)
  const [userSettings, setUserSettings] = useState<{
    streamingQuality: "low" | "normal" | "high" | "very_high"
    dataSaver: boolean
  }>({
    streamingQuality: "high",
    dataSaver: false,
  })
  const [networkQuality, setNetworkQuality] = useState<"low" | "normal" | "high" | "very_high">("high")

  const audioRef = useRef<HTMLAudioElement | null>(null)
  const hasUserInteracted = useRef(false)
  const pendingPlayRef = useRef<Track | null>(null)
  const currentAudioUrlRef = useRef<string>("")

  useEffect(() => {
    if (previousUserIdRef.current !== currentUserId) {
      if (previousUserIdRef.current !== null) {
        if (audioRef.current) {
          audioRef.current.pause()
          audioRef.current.src = ""
        }

        setCurrentTrack(null)
        setIsPlaying(false)
        setProgress(0)
        setQueue([])
        setQueueIndex(0)
        setLikedTracks(new Set())
        setDownloadedTracks(new Set())
        setRecentlyPlayed([])
        setIsPlayerVisible(false)

        offlineStorage?.clearUserSession()
      }

      previousUserIdRef.current = currentUserId
    }
  }, [currentUserId])

  useEffect(() => {
    async function initUserStorage() {
      if (!currentUserId) return

      try {
        // Load likes from database
        const likesRes = await fetch(`/api/users/${currentUserId}/liked-tracks`)
        if (likesRes.ok) {
          const likesData = await likesRes.json()
          const likedIds = (likesData.tracks || []).map((t: any) => t.id)
          setLikedTracks(new Set(likedIds))
        }

        // Load downloaded tracks from IndexedDB
        if (offlineStorage) {
          await offlineStorage.initForUser(currentUserId)
          const tracks = await offlineStorage.getAllTracks()
          setDownloadedTracks(new Set(tracks.map((t) => t.id)))
        }
      } catch (error) {
        console.error("Failed to init user storage:", error)
      }
    }

    initUserStorage()
  }, [currentUserId])

  useEffect(() => {
    function updateOnlineStatus() {
      const isOnline = navigator.onLine
      setIsOfflineMode(!isOnline)

      if (!isOnline) {
        console.log("[v0] App is now offline - only downloaded tracks can be played")
        toast.info("Mode hors ligne - Seules les musiques telechargees sont disponibles")
      } else {
        console.log("[v0] App is back online")
      }
    }

    updateOnlineStatus()

    window.addEventListener("online", updateOnlineStatus)
    window.addEventListener("offline", updateOnlineStatus)

    return () => {
      window.removeEventListener("online", updateOnlineStatus)
      window.removeEventListener("offline", updateOnlineStatus)
    }
  }, [])

  useEffect(() => {
    const audio = new Audio()
    audio.preload = "auto"
    audio.volume = volume / 100
    audio.crossOrigin = "anonymous"
    audio.setAttribute("playsinline", "true")
    audio.setAttribute("webkit-playsinline", "true")
    audioRef.current = audio

    const handleEnded = () => {
      if (repeatMode === "one") {
        audio.currentTime = 0
        audio.play().catch(console.error)
      } else {
        nextTrack()
      }
    }

    const handleTimeUpdate = () => {
      setProgress(audio.currentTime)
    }

    const handleCanPlay = () => {
      setIsLoading(false)
      if (pendingPlayRef.current && hasUserInteracted.current) {
        audio.play().catch((error) => {
          console.error("Playback failed:", error)
          setIsPlaying(false)
        })
        pendingPlayRef.current = null
      }
    }

    const handleWaiting = () => {
      setIsLoading(true)
    }

    const handleError = (e: Event) => {
      const error = audio.error
      if (!error) return
      if (!audio.src || audio.src === window.location.href) return

      let errorMessage = "Unknown error"
      switch (error.code) {
        case MediaError.MEDIA_ERR_ABORTED:
          errorMessage = "Audio loading aborted"
          break
        case MediaError.MEDIA_ERR_NETWORK:
          errorMessage = "Network error while loading audio"
          break
        case MediaError.MEDIA_ERR_DECODE:
          errorMessage = "Audio decoding error"
          break
        case MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED:
          errorMessage = "Audio source not supported or file not found"
          break
      }

      console.error(`[Player] Playback error: ${errorMessage}`, {
        errorCode: error.code,
        src: audio.src,
        networkState: audio.networkState,
        readyState: audio.readyState,
      })

      setIsLoading(false)
      setIsPlaying(false)

      toast.error(`Erreur de lecture: ${errorMessage}`)
    }

    const handlePlaying = () => {
      setIsLoading(false)
      setIsPlaying(true)
    }

    const handlePause = () => {
      setIsPlaying(false)
    }

    const handleLoadStart = () => {
      setIsLoading(true)
    }

    audio.addEventListener("ended", handleEnded)
    audio.addEventListener("timeupdate", handleTimeUpdate)
    audio.addEventListener("canplay", handleCanPlay)
    audio.addEventListener("waiting", handleWaiting)
    audio.addEventListener("error", handleError)
    audio.addEventListener("playing", handlePlaying)
    audio.addEventListener("pause", handlePause)
    audio.addEventListener("loadstart", handleLoadStart)

    return () => {
      audio.removeEventListener("ended", handleEnded)
      audio.removeEventListener("timeupdate", handleTimeUpdate)
      audio.removeEventListener("canplay", handleCanPlay)
      audio.removeEventListener("waiting", handleWaiting)
      audio.removeEventListener("error", handleError)
      audio.removeEventListener("playing", handlePlaying)
      audio.removeEventListener("pause", handlePause)
      audio.removeEventListener("loadstart", handleLoadStart)
      audio.pause()
      audio.src = ""
    }
  }, [])

  useEffect(() => {
    const audio = audioRef.current
    if (!currentTrack || !audio) return
    if (!currentTrack.audioUrl) {
      console.error("[Player] No audio URL for track:", currentTrack.title)
      toast.error("Ce titre n'a pas de fichier audio disponible")
      return
    }

    if (currentAudioUrlRef.current === currentTrack.audioUrl) {
      return
    }

    const loadAndPlay = async () => {
      setIsLoading(true)

      try {
        let resolved: { url: string; mimeType: string }

        if (currentTrack.audioUrl.startsWith("blob:")) {
          console.log("[Player] Using offline blob URL directly:", currentTrack.audioUrl)
          resolved = { url: currentTrack.audioUrl, mimeType: "audio/mpeg" }
        } else {
          resolved = (await resolveAudioUrl(currentTrack.audioUrl, currentTrack.id)) || {
            url: currentTrack.audioUrl,
            mimeType: "audio/mpeg",
          }
        }

        if (!resolved) {
          throw new Error("Could not resolve audio URL")
        }

        console.log("[Player] Loading track:", currentTrack.title, {
          originalUrl: currentTrack.audioUrl,
          resolvedUrl: resolved.url,
          mimeType: resolved.mimeType,
          isOffline: currentTrack.isOffline,
        })

        currentAudioUrlRef.current = currentTrack.audioUrl

        audio.src = resolved.url
        audio.load()

        if (isPlaying && hasUserInteracted.current) {
          try {
            await audio.play()
          } catch (playError: any) {
            if (playError.name === "NotAllowedError") {
              console.warn("[Player] Autoplay blocked, waiting for user interaction")
              pendingPlayRef.current = currentTrack
            } else if (playError.name !== "AbortError") {
              throw playError
            }
          }
        }
      } catch (error) {
        console.error("[Player] Error loading audio:", error)
        setIsLoading(false)
        setIsPlaying(false)
        currentAudioUrlRef.current = ""

        toast.error("Impossible de charger ce titre. Passage au suivant...")

        setTimeout(() => {
          if (queue.length > queueIndex + 1) {
            nextTrack()
          }
        }, 1500)
      }
    }

    loadAndPlay()
  }, [currentTrack])

  useEffect(() => {
    const audio = audioRef.current
    if (!audio || !currentTrack) return

    if (isPlaying) {
      if (audio.paused && audio.src && audio.readyState >= 2) {
        audio.play().catch((error) => {
          if (error.name !== "AbortError") {
            console.error("[Player] Play error:", error)
            setIsPlaying(false)
          }
        })
      }
    } else {
      if (!audio.paused) {
        audio.pause()
      }
    }
  }, [isPlaying, currentTrack])

  useEffect(() => {
    if (typeof navigator === "undefined" || !("mediaSession" in navigator)) return
    navigator.mediaSession.playbackState = isPlaying ? "playing" : "paused"
  }, [isPlaying])

  useEffect(() => {
    if (audioRef.current) {
      audioRef.current.volume = volume / 100
    }
  }, [volume])

  useEffect(() => {
    let interval: NodeJS.Timeout
    if (sleepTimerRemaining !== null && sleepTimerRemaining > 0 && isPlaying) {
      interval = setInterval(() => {
        setSleepTimerRemaining((prev) => {
          if (prev === null || prev <= 1) {
            setIsPlaying(false)
            setSleepTimerMinutes(null)
            return null
          }
          return prev - 1
        })
      }, 1000)
    }
    return () => clearInterval(interval)
  }, [sleepTimerRemaining, isPlaying])

  useEffect(() => {
    if (currentUserId && offlineStorage && likedTracks.size > 0) {
      offlineStorage.saveUserData({ liked_tracks: Array.from(likedTracks) }).catch(console.error)
    }
  }, [likedTracks, currentUserId])

  const recordStream = useCallback(
    async (track: Track) => {
      if (!currentUserId) return

      try {
        await fetch("/api/history", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({
            userId: currentUserId,
            trackId: track.id,
          }),
        })
      } catch (error) {
        console.error("Failed to record stream:", error)
      }
    },
    [currentUserId],
  )

  const playTrack = useCallback(
    async (track: Track) => {
      console.log(
        "[v0] Playing track:",
        track.title,
        "Offline mode:",
        isOfflineMode,
        "Is downloaded:",
        downloadedTracks.has(track.id),
      )

      console.log("[v0] [playTrack] Received track:", {
        id: track.id,
        title: track.title,
        image: track.image,
        cover_url: track.cover_url,
        album_cover: track.album_cover,
        hasImage: !!track.image,
        hasCoverUrl: !!track.cover_url,
        hasAlbumCover: !!track.album_cover,
      })

      if (isOfflineMode && !downloadedTracks.has(track.id)) {
        console.warn("[v0] Cannot play track in offline mode - not downloaded:", track.id)
        toast.error("Cette musique n'est pas telechargee - non disponible hors ligne")
        return
      }

      let finalAudioUrl = track.audioUrl
      if (downloadedTracks.has(track.id)) {
        try {
          console.log("[v0] Track is downloaded, loading from offline storage...")
          const offlineBlob = await offlineStorage?.getAudioBlob(track.id)
          if (offlineBlob) {
            // Clean up previous blob URL to prevent memory leaks
            if (currentAudioUrlRef.current && currentAudioUrlRef.current.startsWith("blob:")) {
              URL.revokeObjectURL(currentAudioUrlRef.current)
            }
            finalAudioUrl = URL.createObjectURL(offlineBlob)
            console.log("[v0] Using offline audio blob URL for track:", track.id)
          } else {
            console.warn("[v0] Track marked as downloaded but no blob found:", track.id)
            if (isOfflineMode) {
              toast.error("Fichier audio introuvable dans le stockage hors ligne")
              return
            }
          }
        } catch (error) {
          console.error("[v0] Failed to load offline audio:", error)
          if (isOfflineMode) {
            toast.error("Impossible de charger la musique hors ligne")
            return
          }
        }
      }

      if (!finalAudioUrl) {
        console.error("[v0] No audio URL available for track:", track.id)
        toast.error("URL audio introuvable")
        return
      }

      hasUserInteracted.current = true

      if (currentTrack?.id === track.id) {
        currentAudioUrlRef.current = ""
      }

      const trackWithAudio = { ...track, audioUrl: finalAudioUrl, isOffline: downloadedTracks.has(track.id) }

      setCurrentTrack(trackWithAudio)
      setProgress(0)
      setIsPlaying(true)
      setIsPlayerVisible(true)

      setRecentlyPlayed((prev) => {
        const filtered = prev.filter((t) => t.id !== track.id)
        return [trackWithAudio, ...filtered].slice(0, 20)
      })

      if (!isOfflineMode) {
        recordStream(trackWithAudio)
      }
      onTrackPlay?.(trackWithAudio)
    },
    [currentTrack, onTrackPlay, recordStream, isOfflineMode, downloadedTracks],
  )

  const playAlbum = useCallback(
    (tracks: Track[], startIndex = 0) => {
      hasUserInteracted.current = true

      if (shuffleEnabled) {
        const shuffled = [...tracks].sort(() => Math.random() - 0.5)
        setQueue(shuffled)
        setQueueIndex(0)
        playTrack(shuffled[0])
      } else {
        setQueue(tracks)
        setQueueIndex(startIndex)
        playTrack(tracks[startIndex])
      }
    },
    [shuffleEnabled, playTrack],
  )

  const togglePlay = useCallback(() => {
    hasUserInteracted.current = true
    setIsPlaying((prev) => !prev)
  }, [])

  const nextTrack = useCallback(() => {
    if (queue.length === 0) return

    let nextIndex = queueIndex + 1

    if (nextIndex >= queue.length) {
      if (repeatMode === "all") {
        nextIndex = 0
      } else {
        setIsPlaying(false)
        return
      }
    }

    setQueueIndex(nextIndex)
    playTrack(queue[nextIndex])
  }, [queue, queueIndex, repeatMode, playTrack])

  const previousTrack = useCallback(() => {
    if (progress > 3) {
      setProgress(0)
      if (audioRef.current) {
        audioRef.current.currentTime = 0
      }
      return
    }

    if (queue.length === 0) return

    let prevIndex = queueIndex - 1
    if (prevIndex < 0) {
      if (repeatMode === "all") {
        prevIndex = queue.length - 1
      } else {
        prevIndex = 0
      }
    }

    setQueueIndex(prevIndex)
    playTrack(queue[prevIndex])
  }, [queue, queueIndex, progress, repeatMode, playTrack])

  const seekTo = useCallback((position: number) => {
    setProgress(position)
    if (audioRef.current) {
      audioRef.current.currentTime = position
    }
  }, [])

  const setVolume = useCallback((vol: number) => {
    setVolumeState(vol)
  }, [])

  const toggleShuffle = useCallback(() => {
    setShuffleEnabled((prev) => {
      if (!prev && queue.length > 0) {
        const currentTrackInQueue = queue[queueIndex]
        const remaining = queue.filter((_, i) => i !== queueIndex)
        const shuffled = remaining.sort(() => Math.random() - 0.5)
        setQueue([currentTrackInQueue, ...shuffled])
        setQueueIndex(0)
      }
      return !prev
    })
  }, [queue, queueIndex])

  const setRepeatMode = useCallback((mode: RepeatMode) => {
    setRepeatModeState(mode)
  }, [])

  const addToQueue = useCallback((track: Track) => {
    setQueue((prev) => [...prev, track])
  }, [])

  const removeFromQueue = useCallback(
    (index: number) => {
      setQueue((prev) => prev.filter((_, i) => i !== index))
      if (index < queueIndex) {
        setQueueIndex((prev) => prev - 1)
      }
    },
    [queueIndex],
  )

  const clearQueue = useCallback(() => {
    setQueue(currentTrack ? [currentTrack] : [])
    setQueueIndex(0)
  }, [currentTrack])

  const moveInQueue = useCallback((fromIndex: number, toIndex: number) => {
    setQueue((prev) => {
      const newQueue = [...prev]
      const [removed] = newQueue.splice(fromIndex, 1)
      newQueue.splice(toIndex, 0, removed)
      return newQueue
    })
    setQueueIndex((prev) => {
      if (fromIndex === prev) return toIndex
      if (fromIndex < prev && toIndex >= prev) return prev - 1
      if (fromIndex > prev && toIndex <= prev) return prev + 1
      return prev
    })
  }, [])

  const toggleLike = useCallback(async (trackId: string) => {
    if (!currentUserId) {
      toast.error("Connectez-vous pour aimer des titres")
      return
    }

    const wasLiked = likedTracks.has(trackId)
    
    // Optimistic update
    setLikedTracks((prev) => {
      const next = new Set(prev)
      if (next.has(trackId)) {
        next.delete(trackId)
      } else {
        next.add(trackId)
      }
      return next
    })

    try {
      if (wasLiked) {
        // Unlike
        const res = await fetch(`/api/tracks/${trackId}/like?userId=${currentUserId}`, {
          method: "DELETE",
        })
        if (!res.ok) throw new Error("Failed to unlike")
      } else {
        // Like
        const res = await fetch(`/api/tracks/${trackId}/like`, {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ userId: currentUserId }),
        })
        if (!res.ok) throw new Error("Failed to like")
      }
    } catch (error) {
      // Rollback on error
      setLikedTracks((prev) => {
        const next = new Set(prev)
        if (wasLiked) {
          next.add(trackId)
        } else {
          next.delete(trackId)
        }
        return next
      })
      toast.error("Impossible de mettre a jour le like")
    }
  }, [currentUserId, likedTracks])

  const isLiked = useCallback(
    (trackId: string) => {
      return likedTracks.has(trackId)
    },
    [likedTracks],
  )

  const toggleDownload = useCallback(async (trackId: string) => {
    if (!currentUserId) {
      toast.error("Connectez-vous pour telecharger des titres")
      return
    }

    const wasDownloaded = downloadedTracks.has(trackId)

    if (wasDownloaded) {
      // Delete downloaded track
      try {
        if (offlineStorage) {
          await offlineStorage.deleteTrack(trackId)
        }
        setDownloadedTracks((prev) => {
          const next = new Set(prev)
          next.delete(trackId)
          return next
        })
        toast.success("Telechargement supprime")
      } catch (error) {
        toast.error("Impossible de supprimer le telechargement")
      }
    } else {
      // Download track - find track info from current track or queue
      const trackInfo = currentTrack?.id === trackId ? currentTrack : queue.find(t => t.id === trackId)
      
      if (!trackInfo) {
        toast.error("Informations du titre non disponibles")
        return
      }

      toast.info(`Telechargement de "${trackInfo.title}" en cours...`)

      try {
        if (offlineStorage) {
          await offlineStorage.initForUser(currentUserId)
          const success = await offlineStorage.downloadTrackForOffline({
            id: trackInfo.id,
            title: trackInfo.title,
            artist: trackInfo.artist,
            album: trackInfo.album,
            cover_url: trackInfo.cover_url || trackInfo.image,
            duration_ms: (trackInfo.duration || 0) * 1000,
            audio_url: trackInfo.audioUrl || `/api/stream/${trackInfo.id}`,
          })

          if (success) {
            setDownloadedTracks((prev) => {
              const next = new Set(prev)
              next.add(trackId)
              return next
            })
            toast.success(`"${trackInfo.title}" est disponible hors ligne`)
          } else {
            throw new Error("Download failed")
          }
        }
      } catch (error) {
        toast.error("Impossible de telecharger le titre")
      }
    }
  }, [currentUserId, downloadedTracks, currentTrack, queue])

  const isDownloaded = useCallback(
    (trackId: string) => {
      return downloadedTracks.has(trackId)
    },
    [downloadedTracks],
  )

  const setSleepTimer = useCallback((minutes: number | null) => {
    setSleepTimerMinutes(minutes)
    if (minutes !== null) {
      setSleepTimerRemaining(minutes * 60)
    } else {
      setSleepTimerRemaining(null)
    }
  }, [])

  const cancelSleepTimer = useCallback(() => {
    setSleepTimerMinutes(null)
    setSleepTimerRemaining(null)
  }, [])

  const hidePlayer = useCallback(() => {
    setIsPlayerVisible(false)
  }, [])

  const showPlayer = useCallback(() => {
    setIsPlayerVisible(true)
  }, [])

  const stopPlayback = useCallback(() => {
    if (audioRef.current) {
      audioRef.current.pause()
      audioRef.current.currentTime = 0
      audioRef.current.src = ""
    }
    currentAudioUrlRef.current = ""
    setCurrentTrack(null)
    setIsPlaying(false)
    setProgress(0)
    setIsPlayerVisible(false)
  }, [])

  const setOnTrackPlay = useCallback((callback: ((track: Track) => void) | undefined) => {
    setOnTrackPlayState(() => callback)
  }, [])

  const updateStreamingSettings = useCallback(
    (settings: { streamingQuality?: "low" | "normal" | "high" | "very_high"; dataSaver?: boolean }) => {
      setUserSettings((prev) => ({
        ...prev,
        ...settings,
      }))
    },
    [],
  )

  return (
    <PlayerContext.Provider
      value={{
        currentTrack,
        isPlaying,
        progress,
        volume,
        queue,
        queueIndex,
        shuffleEnabled,
        repeatMode,
        likedTracks,
        downloadedTracks,
        recentlyPlayed,
        sleepTimerMinutes,
        sleepTimerRemaining,
        isPlayerVisible,
        isOfflineMode,
        isLoading,
        playTrack,
        playAlbum,
        togglePlay,
        nextTrack,
        previousTrack,
        seekTo,
        setVolume,
        toggleShuffle,
        setRepeatMode,
        addToQueue,
        removeFromQueue,
        clearQueue,
        moveInQueue,
        toggleLike,
        isLiked,
        toggleDownload,
        isDownloaded,
        setSleepTimer,
        cancelSleepTimer,
        hidePlayer,
        showPlayer,
        stopPlayback,
        onTrackPlay,
        setOnTrackPlay,
        updateStreamingSettings,
      }}
    >
      {children}
    </PlayerContext.Provider>
  )
}

export function usePlayer() {
  const context = useContext(PlayerContext)
  if (context === undefined) {
    throw new Error("usePlayer must be used within a PlayerProvider")
  }
  return context
}
