import { useEffect, useRef } from 'react'
import type { Song } from './types'
import { loadYouTubeApi } from '../../game/audioPlayer'

const PREVIEW_DELAY_MS = 300
const PREVIEW_START_SEC = 30
const FADE_IN_MS = 1000
const FADE_STEP_MS = 50
const MAX_VOLUME = 0.5

/**
 * Plays a song preview. For YouTube songs, mounts a player into `ytHostEl`.
 * The caller must render a visible container and pass it via ref.
 */
export function useSongPreview(song: Song, ytHostEl: HTMLElement | null) {
  const cleanupRef = useRef<(() => void) | null>(null)

  useEffect(() => {
    cleanupRef.current?.()
    cleanupRef.current = null

    if (song.youtubeVideoId && ytHostEl) {
      const cleanup = startYouTubePreview(song, ytHostEl)
      cleanupRef.current = cleanup
      return cleanup
    }

    const cleanup = startLocalPreview(song)
    cleanupRef.current = cleanup
    return cleanup
  }, [song.id, ytHostEl])
}

// ---------------------------------------------------------------------------
// Local audio preview
// ---------------------------------------------------------------------------

function startLocalPreview(song: Song): () => void {
  let audio: HTMLAudioElement | null = null
  let fadeIv = 0
  const timer = window.setTimeout(() => {
    audio = new Audio(song.audioUrl)
    audio.currentTime = PREVIEW_START_SEC
    audio.volume = 0
    audio.play().then(() => {
      const step = (MAX_VOLUME * FADE_STEP_MS) / FADE_IN_MS
      fadeIv = window.setInterval(() => {
        if (!audio) return
        if (audio.volume + step >= MAX_VOLUME) {
          audio.volume = MAX_VOLUME
          clearInterval(fadeIv)
        } else {
          audio.volume = Math.min(MAX_VOLUME, audio.volume + step)
        }
      }, FADE_STEP_MS)
    }).catch(() => {})
  }, PREVIEW_DELAY_MS)

  return () => {
    clearTimeout(timer)
    clearInterval(fadeIv)
    if (audio) { audio.pause(); audio.src = '' }
  }
}

// ---------------------------------------------------------------------------
// YouTube preview (visible player)
// ---------------------------------------------------------------------------

function startYouTubePreview(song: Song, host: HTMLElement): () => void {
  let destroyed = false
  let player: YT.Player | null = null
  let fadeIv = 0

  // Clear any previous player content and show spinner
  host.innerHTML = ''
  host.classList.add('yt-loading')

  const timer = window.setTimeout(() => {
    loadYouTubeApi().then(() => {
      if (destroyed) return

      const div = document.createElement('div')
      host.appendChild(div)

      const offset = song.youtubeOffset ?? 0
      const seekTo = offset + PREVIEW_START_SEC

      player = new YT.Player(div, {
        videoId: song.youtubeVideoId!,
        width: '100%',
        height: '100%',
        playerVars: {
          autoplay: 1,
          controls: 0,
          disablekb: 1,
          fs: 0,
          modestbranding: 1,
          rel: 0,
          playsinline: 1,
          start: Math.floor(seekTo),
        },
        events: {
          onReady() {
            if (destroyed || !player) return
            player.setVolume(0)
            player.seekTo(seekTo, true)
            player.playVideo()
          },
          onStateChange(e: YT.OnStateChangeEvent) {
            if (destroyed || !player) return
            if (e.data === YT.PlayerState.PLAYING) {
              host.classList.remove('yt-loading')
              const maxVol = MAX_VOLUME * 100
              const step = (maxVol * FADE_STEP_MS) / FADE_IN_MS
              fadeIv = window.setInterval(() => {
                if (!player || destroyed) { clearInterval(fadeIv); return }
                const cur = player.getVolume()
                if (cur + step >= maxVol) {
                  player.setVolume(maxVol)
                  clearInterval(fadeIv)
                } else {
                  player.setVolume(cur + step)
                }
              }, FADE_STEP_MS)
            }
          },
        },
      })
    }).catch(() => {})
  }, PREVIEW_DELAY_MS)

  return () => {
    destroyed = true
    clearTimeout(timer)
    clearInterval(fadeIv)
    if (player) {
      try { player.destroy() } catch { /* ignore */ }
    }
    host.innerHTML = ''
  }
}
