import { create } from 'zustand'
import type { BaseItemDto } from '../api/types'

/**
 * Music playback queue + transport state. Drives the MiniPlayer and the
 * NowPlaying expanded view. Separate from the video player (PlayerPage),
 * which has its own runtime store for session-only state like A-B loops
 * and subtitle offsets.
 */
interface MusicState {
  currentTrack: BaseItemDto | null
  isPlaying: boolean
  currentTime: number
  duration: number
  volume: number
  isMuted: boolean
  queue: BaseItemDto[]
  queueIndex: number
  shuffle: boolean
  repeat: 'off' | 'all' | 'one'

  playTrack: (track: BaseItemDto, queue?: BaseItemDto[]) => void
  pause: () => void
  resume: () => void
  stop: () => void
  seekTo: (time: number) => void
  setVolume: (vol: number) => void
  toggleMute: () => void
  nextTrack: () => void
  prevTrack: () => void
  toggleShuffle: () => void
  cycleRepeat: () => void
  addToQueue: (items: BaseItemDto | BaseItemDto[]) => void
  removeFromQueue: (index: number) => void
  clearQueue: () => void
  setCurrentTime: (time: number) => void
  setDuration: (duration: number) => void
  setPlaying: (playing: boolean) => void
}

function shuffleArray<T>(arr: T[]): T[] {
  const shuffled = [...arr]
  for (let i = shuffled.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1))
    ;[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]]
  }
  return shuffled
}

export const useMusicStore = create<MusicState>((set, get) => ({
  currentTrack: null,
  isPlaying: false,
  currentTime: 0,
  duration: 0,
  volume: 1,
  isMuted: false,
  queue: [],
  queueIndex: -1,
  shuffle: false,
  repeat: 'off',

  playTrack: (track, queue) => {
    const state = get()
    const newQueue = queue || [track]
    const idx = newQueue.findIndex(t => t.Id === track.Id)
    set({
      currentTrack: track,
      isPlaying: true,
      queue: state.shuffle ? shuffleArray(newQueue) : newQueue,
      queueIndex: state.shuffle ? 0 : Math.max(0, idx),
      currentTime: 0,
      duration: 0,
    })
  },

  pause: () => set({ isPlaying: false }),
  resume: () => set({ isPlaying: true }),
  stop: () => set({ currentTrack: null, isPlaying: false, currentTime: 0 }),
  seekTo: (time) => set({ currentTime: time }),
  setVolume: (vol) => set({ volume: Math.max(0, Math.min(1, vol)) }),
  toggleMute: () => set(s => ({ isMuted: !s.isMuted })),

  nextTrack: () => {
    const { queue, queueIndex, repeat } = get()
    if (queue.length === 0) return

    let next = queueIndex + 1
    if (next >= queue.length) {
      if (repeat === 'all') next = 0
      else if (repeat === 'one') next = queueIndex
      else { set({ isPlaying: false }); return }
    }
    set({ queueIndex: next, currentTrack: queue[next], currentTime: 0, isPlaying: true })
  },

  prevTrack: () => {
    const { queue, queueIndex, currentTime } = get()
    if (queue.length === 0) return
    if (currentTime > 3) {
      set({ currentTime: 0 })
      return
    }
    const prev = Math.max(0, queueIndex - 1)
    set({ queueIndex: prev, currentTrack: queue[prev], currentTime: 0, isPlaying: true })
  },

  toggleShuffle: () => {
    const { shuffle, queue, currentTrack } = get()
    if (!shuffle) {
      const shuffled = shuffleArray(queue)
      if (currentTrack) {
        const idx = shuffled.findIndex(t => t.Id === currentTrack.Id)
        if (idx > 0) {
          ;[shuffled[0], shuffled[idx]] = [shuffled[idx], shuffled[0]]
        }
      }
      set({ shuffle: true, queue: shuffled, queueIndex: 0 })
    } else {
      const current = currentTrack
      const original = [...queue].sort((a, b) =>
        (a.SortName || a.Name || '').localeCompare(b.SortName || b.Name || '')
      )
      const idx = current ? original.findIndex(t => t.Id === current.Id) : 0
      set({ shuffle: false, queue: original, queueIndex: Math.max(0, idx) })
    }
  },

  cycleRepeat: () => set(s => ({
    repeat: s.repeat === 'off' ? 'all' : s.repeat === 'all' ? 'one' : 'off'
  })),

  addToQueue: (items) => set(s => ({
    queue: [...s.queue, ...(Array.isArray(items) ? items : [items])]
  })),

  removeFromQueue: (index) => set(s => ({
    queue: s.queue.filter((_, i) => i !== index)
  })),

  clearQueue: () => set({ queue: [], queueIndex: -1 }),
  setCurrentTime: (time) => set({ currentTime: time }),
  setDuration: (duration) => set({ duration }),
  setPlaying: (playing) => set({ isPlaying: playing }),
}))
