import {
  APICreate,
  APIListPaginated,
  APIRemove,
  APIRetrieve,
  APIUpdate,
  createExtendableAPI,
} from '@rokoli/bnb/drf'
import { defineStore } from 'pinia'

import { createTankURL } from '@/api'
import { tankAuthInit } from '@/stores/auth'
import { Playlist } from '@/types'
import { URLBuilder } from '@rokoli/bnb'
import { useShowStore } from '@/stores/shows'
import { computed, MaybeRefOrGetter, toValue } from 'vue'

export function calculatePlaylistDurationInSeconds(playlist: Playlist, skipUnknown?: true): number
export function calculatePlaylistDurationInSeconds(
  playlist: Playlist,
  skipUnknown?: false,
): number | null

/**
 * Calculates the duration of a playlist.
 * May return null if the playlist contains entries with an invalid duration.
 * @param playlist
 * @param skipUnknown Whether unknown length entries should be skipped
 */
export function calculatePlaylistDurationInSeconds(playlist: Playlist, skipUnknown = false) {
  let duration = 0
  for (const entry of playlist.entries) {
    // entry.duration may be null/NaN if the entry references
    // a stream or other resources without an inherent duration
    if (typeof entry.duration !== 'number' || isNaN(entry.duration)) {
      if (skipUnknown) continue
      else return null
    }
    duration += entry.duration
  }

  return duration
}

export function countUnknownDurations(entries: Playlist['entries']) {
  let counter = 0
  for (const entry of entries) {
    if (typeof entry.duration !== 'number' || isNaN(entry.duration)) counter += 1
  }
  return counter
}

export function usePlaylistState(
  playlist: MaybeRefOrGetter<Playlist | null>,
  targetDurationSeconds: MaybeRefOrGetter<number>,
) {
  return computed(() => {
    const _playlist = toValue(playlist)
    if (!_playlist) return { state: 'missing' as const }
    const _targetDuration = Math.round(toValue(targetDurationSeconds))
    const unknownDurationCount = countUnknownDurations(_playlist.entries)
    let playlistDuration = Math.round(calculatePlaylistDurationInSeconds(_playlist, true))

    // If the playlist contains just one record of unknown length
    // the playout will automatically expand that entry to the remaining
    // time that is needed to fill the timeslot.
    // We can therefore consider a single entry of unknown duration to fit the required time.
    if (unknownDurationCount === 1 && playlistDuration < _targetDuration) {
      playlistDuration = _targetDuration
    }

    if (unknownDurationCount > 1)
      return {
        state: 'indeterminate' as const,
        duration: playlistDuration,
        offset: Math.abs(_targetDuration - playlistDuration),
      }
    if (playlistDuration < _targetDuration)
      return {
        state: 'tooShort' as const,
        duration: playlistDuration,
        offset: _targetDuration - playlistDuration,
      }
    if (playlistDuration > _targetDuration)
      return {
        state: 'tooLong' as const,
        duration: playlistDuration,
        offset: playlistDuration - _targetDuration,
      }

    return { state: 'ok' as const }
  })
}

const playlistsShowEndpoint: URLBuilder = (...subPaths) => {
  const showStore = useShowStore()
  return createTankURL.prefix(
    'shows',
    showStore.selectedShow?.slug as string,
    'playlists',
  )(...subPaths)
}

export const usePlaylistStore = defineStore('playlists', () => {
  const endpoint = createTankURL.prefix('playlists')
  const { api, base } = createExtendableAPI<Playlist>(endpoint, tankAuthInit)
  const { list } = APIListPaginated(api)
  const { update } = APIUpdate({ ...api, endpoint: playlistsShowEndpoint })
  return {
    ...base,
    list,
    update,
    ...APIRetrieve(api),
    ...APICreate({ ...api, endpoint: playlistsShowEndpoint }),
    ...APIRemove({ ...api, endpoint: playlistsShowEndpoint }),
  }
})