local BGM = {}              -- KEY: track_name; VALUE: {name, description, params = MT params}
local SFX = {}              -- KEY: track_name; VALUE: {name, description, params = MT params}
-- i nomi delle tracce sono le cose più gettonate, per questo salvate anche a parte:
-- così da non dover copiare tabelle su tabelle ogni volta
local now_playing = {}      -- KEY: p_name; VALUE: {BGM = name, -- SFX = {name1, name2}, whatever = {},
                                                    -- _data = {bgm = {name, description, handle, started_at, params}, prev_bgm = {name, description, started_at, params},
                                                    -- sfx = {[name1] = {handle1, params}, [name2] = {handle2, params}}}}
                                                     -- TODO registra categorie personalizzate, se già non esistono
                                                     -- TODO: sfx non implementato

-- TODO opzione accessibilità che mostra sx - centro - dx da dove viene il suono e intensità. SE BGM, al centro con notina

-- TODO
function audio_lib.play_sound(track_name, params) end
function audio_lib.stop_stound(track_name) end
function audio_lib.get_sounds_of_type(type) end
function audio_lib.get_player_sfx(p_name, in_detail) end
function audio_lib.get_player_sounds_of_type(type) end -- TODO o get_player_sounds e (sopra) get_sounds?



-- INTERNAL ONLY
function audio_lib.init_player(p_name)
  audio_lib.load_settings(p_name)
  now_playing[p_name] = {_data = {bgm = {}, prev_bgm = {}, sfx = {}}}
end



function audio_lib.dealloc_player(p_name)
  now_playing[p_name] = nil
end





----------------------------------------------
---------------------CORE---------------------
----------------------------------------------

-- PROMEMORIA: su arena_lib lancialo quando carica le varie arene
function audio_lib.register_sound(s_type, track_name, desc, def)
  assert(type(s_type) == "string", "[AUDIO_LIB] Error! The first parameter in `audio_lib.register_sound` must be a string!")
  assert(desc, "[AUDIO_LIB] Error! Description is mandatory for accessibility reasons (TODO). Let's everyone enjoy videogames!")
  -- TODO assert se traccia audio esiste; fattibile?

  def = def or {}
  def.to_player = nil
  def.object = nil
  def.pos = nil
  def.exclude_player = nil

  if s_type == "bgm" then
    def.loop = true

    BGM[track_name] = {
      name = track_name,
      description = desc,
      params = def.params or {}
    }

  elseif s_type == "sfx" then
    SFX[track_name] = {
      name = track_name,
      description = desc,
      params = def.params or {}
    }
  end -- TODO categorie personalizzate
end



-- TODO: passare tabella se si vogliono incolonnare più canzoni
function audio_lib.play_bgm(p_name, track_name, override_params)
  if not minetest.get_player_by_name(p_name) then return end

  local audio = table.copy(BGM[track_name])
  local params = audio.params

  if override_params then
    for k, v in pairs(override_params) do
      params[k] = v
    end
  end

  audio.started_at = minetest.get_us_time()
  params.to_player = p_name

  -- se c'era già una canzone in corso
  if now_playing[p_name].bgm then
    -- se è la stessa, fermati
    if now_playing[p_name].bgm == track_name then return end

    local _data = now_playing[p_name]._data
    local curr_bgm = table.copy(_data.bgm)

    _data.prev_bgm = table.copy(_data.bgm)
    _data.prev_bgm.handle = nil
    _data.prev_bgm.params.start_time = (_data.prev_bgm.params.start_time or 0) + (minetest.get_us_time() - curr_bgm.started_at) / 1000000

    minetest.sound_stop(curr_bgm.handle)
  end

  local p_settings = audio_lib.get_settings(p_name)

  params.gain = (params.gain or 1) * (p_settings.volume_bgm / 100) * (p_settings.volume_main / 100)
  local handle = minetest.sound_play(track_name, params)

  audio.handle = handle
  now_playing[p_name].bgm = track_name
  now_playing[p_name]._data.bgm = audio
end



-- TODO: aspettando MT 5.8, start_time aggiunto con quella versione
function audio_lib.continue_bgm(p_name)
  local _data = now_playing[p_name]._data

  if not _data.prev_bgm then return end

  local prev_bgm = _data.prev_bgm

  audio_lib.play_bgm(p_name, prev_bgm.name, { start_time = prev_bgm.params.start_time })
end



function audio_lib.stop_bgm(p_name)
  if not now_playing[p_name].bgm then return end

  local p_playing = now_playing[p_name]
  local _data = p_playing._data

  p_playing.bgm = nil
  _data.prev_bgm = table.copy(_data.bgm)
  _data.bgm = {}

  minetest.sound_stop(_data.prev_bgm.handle)
end



function audio_lib.reload_music(p_name, old_settings)
  local p_playing = now_playing[p_name]
  if not p_playing then return end

  local p_settings = audio_lib.get_settings(p_name)
  local _data = p_playing._data

  if p_playing.bgm then
    local bgm = _data.bgm
    local params = bgm.params

    minetest.sound_stop(bgm.handle)

    -- ottengo il vecchio volume invertendo il calcolo che determina il volume (perché in caso di parametro
    -- sovrascritto tramite play_bgm(..), non mi è possibile ottenerlo da BGM[bgm])
    local old_gain = (params.gain or 1) / (old_settings.volume_bgm / 100) / (old_settings.volume_main / 100)

    params.gain = old_gain * (p_settings.volume_bgm / 100) * (p_settings.volume_main / 100)
    params.start_time = (params.start_time or 0) + (minetest.get_us_time() - bgm.started_at) / 1000000
    bgm.handle = minetest.sound_play(bgm.name, params)
  end

  -- TODO sfx ecc.
end





----------------------------------------------
-----------------GETTERS----------------------
----------------------------------------------

function audio_lib.get_player_bgm(p_name, in_detail)
  local p_playing = now_playing[p_name]
  if not p_playing then return end

  if not in_detail then
    return p_playing.bgm
  else
    return table.copy(p_playing._data.bgm)
  end
end
