-- Sleek RP - Warlock Pets (Audio.lua)
-- Nommage strictement aligné sur le safe_filename Python fourni par Simon.
-- Règle: retire ["“”‘’'.,!?…:;], garde [A-Za-z0-9 _-], collapse espaces -> " ",
-- remplace espaces par "_", tronque à 60, pas de lowercasing, priorité .ogg puis .wav.
-- MODIF: le Core essaie d'abord les packs "assets-only" par pet, puis retombe sur l'audio interne.
-- NEW: Respecte DB.mute_sounds via un petit module SRPWL.Audio (wrappers Play/PlayUI).

local ADDON_NAME, SRPWL = ...
SRPWL = SRPWL or {}
_G.SRPWL = SRPWL

-- =========================
-- DB & defaults
-- =========================
SleekRP_WLP_DB = SleekRP_WLP_DB or {}
local DB = SleekRP_WLP_DB
DB.mute_sounds = (DB.mute_sounds == true) -- false par défaut

-- =========================
-- Module Audio (wrappers sûrs)
-- =========================
SRPWL.Audio = SRPWL.Audio or {}
local Audio = SRPWL.Audio

local DEFAULT_CHANNEL = "SFX"

-- Play un son (SoundKitId ou chemin) en respectant le mute; renvoie true/false
function Audio.Play(fileOrId, channel)
  if DB.mute_sounds then return false end
  local ok = false
  if type(fileOrId) == "number" then
    if PlaySound then
      ok = select(1, pcall(PlaySound, fileOrId, channel or DEFAULT_CHANNEL, true)) == true
    end
  elseif type(fileOrId) == "string" and fileOrId ~= "" then
    if PlaySoundFile then
      -- Certaines versions renvoient un handle, d'autres un bool. On encapsule.
      local r1 = select(1, pcall(PlaySoundFile, fileOrId, channel or DEFAULT_CHANNEL))
      ok = (r1 == true) -- pcall success => on ne sait pas si le fichier existe réellement,
      -- mais WoW ne donne pas d'API de "file exists" fiable côté addon; on complémente plus bas.
    end
  end
  return ok and true or false
end

-- Pour les voix de pets (extension future: routing par petKey, volumes, etc.)
function Audio.PlayPetVoice(petKey, soundPathOrId, channel)
  return Audio.Play(soundPathOrId, channel or DEFAULT_CHANNEL)
end

-- Petit blip UI (SoundKitId)
function Audio.PlayUI(soundKitId)
  if DB.mute_sounds then return false end
  if type(soundKitId) == "number" and PlaySound then
    return select(1, pcall(PlaySound, soundKitId, "SFX", true)) == true
  end
  return false
end

-- Arrêt global (placeholder si tu gères des handles avec StopSound plus tard)
Audio._handles = Audio._handles or {}
local function StopAllPetSounds()
  -- Exemple si tu stockes des handles:
  -- for h in pairs(Audio._handles) do StopSound(h); Audio._handles[h] = nil end
end

-- Écoute les changements d'options pour couper net les sons longs
local prevHook = SRPWL.OnConfigChanged
SRPWL.OnConfigChanged = function(key, value, db)
  if type(prevHook) == "function" then pcall(prevHook, key, value, db) end
  if key == "mute_sounds" and value == true then
    StopAllPetSounds()
  end
end

-- =========================
-- helpers safe_filename (mimer le Python)
-- =========================
local function strip_punct(s)
  -- retire: [\"“”‘’\'.,!?…:;]
  return (s:gsub('[\\"“”‘’\'.!,%?…:;]', ''))
end

local function keep_whitelist(s)
  -- garde: lettres/chiffres/espace/underscore/hyphen ; retire tout le reste
  return (s:gsub('[^A-Za-z0-9 _%-]', ''))
end

local function collapse_spaces(s)
  -- trim + espaces multiples -> un seul espace
  s = (s:match('^%s*(.-)%s*$') or s)
  return (s:gsub('%s+', ' '))
end

local function to_underscores(s)
  return (s:gsub(' ', '_'))
end

local function truncate(s, maxlen)
  maxlen = maxlen or 60
  if #s > maxlen then s = s:sub(1, maxlen) end
  return s
end

local function safe_filename_like_python(text, max_length)
  text = tostring(text or ""):match('^%s*(.-)%s*$') or ""
  text = strip_punct(text)
  text = keep_whitelist(text)
  text = collapse_spaces(text)
  text = to_underscores(text)
  if #text == 0 then text = "line" end
  text = truncate(text, max_length or 60)
  return text
end

-- =========================
-- tryPlay avec wrapper Audio.Play
-- =========================
local function tryPlay(path, channel)
  -- On tente via Audio.Play, qui respecte le mute.
  -- Note: Audio.Play ne peut pas garantir l'existence du fichier; si WoW ne le trouve pas, il ne joue pas, et c'est silencieux.
  return Audio.Play(path, channel or DEFAULT_CHANNEL)
end

-- =========================
-- Mapping packs (assets-only) par pet
-- =========================
-- Nom de dossier d'addon du pack (racine "Interface\\AddOns\\<folder>\\")
local function packAddonFolderForPet(petKey)
  local map = {
    Succubus   = "SleekRP_Warlock_SuccubusVoice",
    Voidwalker = "SleekRP_Warlock_VoidwalkerVoice",
    Imp        = "SleekRP_Warlock_ImpVoice",
    Felhunter  = "SleekRP_Warlock_FelhunterVoice",
    Felguard   = "SleekRP_Warlock_FelguardVoice",
    -- PetKey "Sayaad" mais le pack public s'appelle "Incubus Voice"
    Sayaad     = "SleekRP_Warlock_IncubusVoice",
  }
  return map[petKey]
end

-- Nom du dossier audio racine dans le pack (Audio_<PetPublic>)
-- NB: le SOUS-DOSSIER final DOIT rester = petKey (ex: .../<Action>/Succubus/..., .../<Action>/Sayaad/ )
local function audioRootFolderForPet(petKey)
  local map = {
    Succubus   = "Audio_Succubus",
    Voidwalker = "Audio_Voidwalker",
    Imp        = "Audio_Imp",
    Felhunter  = "Audio_Felhunter",
    Felguard   = "Audio_Felguard",
    Sayaad     = "Audio_Incubus",  -- pack "Incubus Voice" mais sous-dossier final /Sayaad/
  }
  return map[petKey]
end

-- =========================
-- API principale: jouer une réplique pour un event/pet/texte
-- =========================
-- eventKey/petKey = clés exactes utilisées dans tes fichiers Pet_*.lua
-- text = réplique choisie (servira à générer le nom de fichier)
function SRPWL.AudioPlayFor(eventKey, petKey, text)
  if not (eventKey and petKey and text) then return end
  if DB.mute_sounds then return end -- court-circuit rapide

  local stem = safe_filename_like_python(text)
  local channel = DEFAULT_CHANNEL

  -- 1) Base candidate : pack "assets-only" du pet (s'il est installé ou juste présent)
  local bases = {}
  local packFolder = packAddonFolderForPet(petKey)
  local audioRoot  = audioRootFolderForPet(petKey)
  if packFolder and audioRoot then
    bases[#bases+1] = ("Interface\\AddOns\\%s\\%s\\%s\\%s\\"):format(
      packFolder, audioRoot, eventKey, petKey
    )
  end

  -- 2) Fallback interne (audio embarqué côté Core)
  bases[#bases+1] = ("Interface\\AddOns\\SleekRP_WarlockPets\\Audio\\%s\\%s\\"):format(
    eventKey, petKey
  )

  -- Essais dans l'ordre: .ogg puis .wav sur chaque base
  local ok, used = false, nil
  for _, base in ipairs(bases) do
    local ogg = base .. stem .. ".ogg"
    if tryPlay(ogg, channel) then ok = true; used = ogg; break end
    local wav = base .. stem .. ".wav"
    if tryPlay(wav, channel) then ok = true; used = wav; break end
  end

  if DB.debug then
    if ok then
      print("|cffa9a9ff[SRP-AUDIO]|r OK", used)
    else
      local primary = bases[1] and (bases[1] .. stem .. ".ogg")
        or ("Interface\\AddOns\\SleekRP_WarlockPets\\Audio\\"..eventKey.."\\"..petKey.."\\"..stem..".ogg")
      print("|cffa9a9ff[SRP-AUDIO]|r MISS", primary, "(+ .wav and fallbacks)")
    end
  end
end
