// ~/store/player.ts
import { defineStore } from 'pinia'
import type { Track, Box } from '~/../types/types'
import { useDataStore } from '~/store/data'

export const usePlayerStore = defineStore('player', {
  state: () => ({
    currentTrack: null as Track | null,
    position: 0,
    audio: null as HTMLAudioElement | null,
    isPaused: true,
    progressionLast: 0
  }),

  actions: {
    attachAudio(el: HTMLAudioElement) {
      this.audio = el
      // attach listeners if not already attached (idempotent enough for our use)
      this.audio.addEventListener('play', () => {
        this.isPaused = false
      })
      this.audio.addEventListener('playing', () => {
        this.isPaused = false
      })
      this.audio.addEventListener('pause', () => {
        this.isPaused = true
      })
      this.audio.addEventListener('ended', () => {
        this.isPaused = true
        const track = this.currentTrack
        if (!track) return
        const dataStore = useDataStore()
        if (track.type === 'playlist') {
          const next = dataStore.getNextPlaylistTrack(track)
          if (next && next.boxId === track.boxId) {
            this.playTrack(next)
          }
        } else {
          console.log('ended')
          this.currentTrack = null
        }
      })
    },
    async playBox(box: Box) {
      if (this.currentTrack?.boxId === box.id) {
        this.togglePlay()
      } else {
        const dataStore = useDataStore()
        const first = dataStore.getFirstTrackOfBox(box)
        if (first) {
          await this.playTrack(first)
        }
      }
    },
    async playTrack(track: Track) {
      // mettre à jour la piste courante uniquement après avoir géré le toggle
      if (this.currentTrack && this.currentTrack?.id === track.id) {
        this.togglePlay()
      } else {
        this.currentTrack = track
        if (!this.audio) {
          // fallback: create an audio element and attach listeners
          this.attachAudio(new Audio())
        }

        // Interrompre toute lecture en cours avant de charger une nouvelle source
        const audio = this.audio as HTMLAudioElement
        try {
          audio.pause()
        } catch (_) {}

        // on entre en phase de chargement
        this.isPaused = true
        audio.src = track.url
        audio.load()

        // lancer la lecture (seek si nécessaire une fois les metadata chargées)
        try {
          const wantedStart = track.start ?? 0

          // Attendre que les metadata soient prêtes pour pouvoir positionner currentTime
          await new Promise<void>((resolve) => {
            if (audio.readyState >= 1) return resolve()
            const onLoaded = () => resolve()
            audio.addEventListener('loadedmetadata', onLoaded, { once: true })
          })
          // Appliquer le temps de départ
          audio.currentTime = wantedStart > 0 ? wantedStart : 0
          await new Promise<void>((resolve) => {
            const onCanPlay = () => {
              if (wantedStart > 0 && audio.currentTime < wantedStart - 0.05) {
                audio.currentTime = wantedStart
              }
              resolve()
            }
            if (audio.readyState >= 3) return resolve()
            audio.addEventListener('canplay', onCanPlay, { once: true })
          })
          this.isPaused = false
          await audio.play()
        } catch (err: any) {
          // Ignorer les AbortError (arrivent lorsqu'une nouvelle source est chargée rapidement)
          if (err && err.name === 'AbortError') return
          this.isPaused = true
          console.error('Impossible de lire la piste :', err)
        }
      }
    },

    togglePlay() {
      if (!this.audio) return
      if (this.audio.paused) {
        this.isPaused = false
        this.audio
          .play()
          .then(() => {
            this.isPaused = false
          })
          .catch((err) => console.error(err))
      } else {
        this.audio.pause()
        this.isPaused = true
      }
    },

    updateTime() {
      const audio = this.audio
      if (!audio) return

      // update current position
      this.position = audio.currentTime

      // compute and cache a stable progression value
      const duration = audio.duration
      const progression = (this.position / duration) * 100
      if (!isNaN(progression)) {
        this.progressionLast = progression
      }
      // update current track when changing time in compilation
      const cur = this.currentTrack
      if (cur && cur.type === 'compilation') {
        const dataStore = useDataStore()
        const tracks = dataStore
          .getTracksByboxId(cur.boxId)
          .slice()
          .filter((t) => t.type === 'compilation')
          .sort((a, b) => (a.start ?? 0) - (b.start ?? 0))

        if (tracks.length > 0) {
          const now = audio.currentTime
          // find the last track whose start <= now (fallback to first track)
          let found = tracks[0]
          for (const t of tracks) {
            const s = t.start ?? 0
            if (s <= now) {
              found = t
            } else {
              break
            }
          }
          if (found && found.id !== cur.id) {
            // only update metadata reference; do not reload audio
            this.currentTrack = found
          }
        }
      }
    }
  },

  getters: {
    isCurrentBox: (state) => {
      return (boxId: string) => boxId === state.currentTrack?.boxId
    },

    isPlaylistTrack: () => {
      return (track: Track) => {
        return track.type === 'playlist'
      }
    },

    getCurrentTrack: (state) => state.currentTrack,

    getCurrentBox: (state) => {
      return state.currentTrack ? state.currentTrack.url : null
    },

    getCurrentProgression(state) {
      if (!state.audio) return 0
      const duration = state.audio.duration
      const progression = (state.position / duration) * 100
      return isNaN(progression) ? state.progressionLast : progression
    },

    getCurrentCoverUrl(state) {
      const id = state.currentTrack?.coverId
      if (!id) return null
      return id.startsWith('http') ? id : `https://f4.bcbits.com/img/${id}_4.jpg`
    }
  }
})
