-- Sleek RP - Warlock Pets (Core.lua) — Talking UI only + Chat output
local ADDON_NAME, SRPWL = ...
SRPWL = SRPWL or {}
_G.SRPWL = SRPWL

-- ====== DB (saved vars) ======
SleekRP_WLP_DB = SleekRP_WLP_DB or {}
local DB = SleekRP_WLP_DB

DB.cooldown           = DB.cooldown           or 12
DB.enable_audio       = (DB.enable_audio ~= false)
DB.debug              = (DB.debug == true)

if DB.use_talking_style == nil then DB.use_talking_style = true end
DB.talking_duration   = DB.talking_duration   or 5.0
DB.talking_scale      = DB.talking_scale      or 1.0
DB.talking_lock       = (DB.talking_lock == true)

-- Option partagée avec Events.lua (facteur de vitesse des dialogues/pings)
DB.dialogue_rate      = DB.dialogue_rate      or 1.0

function SRPWL.GetDialogueRate()
  return tonumber(DB.dialogue_rate or 1.0) or 1.0
end

-- User preference for the sayaad family (succubus/incubus)
DB.sayaad_form        = DB.sayaad_form or "succubus" -- "succubus" | "incubus"

function SRPWL.GetSayaadForm()
  return (DB.sayaad_form == "incubus") and "incubus" or "succubus"
end

-- ====== Pet registry ======
local REGISTRY = {}
local PET_KEY_ACTIVE = nil

function SRPWL.RegisterPet(pet)
  if not pet or not pet.key or not pet.dialogues then return end
  REGISTRY[pet.key] = pet
end

function SRPWL.GetPet(key)
  return key and REGISTRY[key] or (PET_KEY_ACTIVE and REGISTRY[PET_KEY_ACTIVE]) or nil
end

function SRPWL.HasEventKey(evKey)
  if not evKey or evKey == "" then return false end
  for _, pet in pairs(REGISTRY) do
    local d = pet and pet.dialogues
    if d and d[evKey] then return true end
  end
  return false
end

-- ====== Robust family detection ======
local function stripAccents(s)
  s = s or ""
  s = s:gsub("[àáâãäå]", "a"):gsub("ç","c"):gsub("[èéêë]","e"):gsub("[ìíîï]","i")
       :gsub("[òóôõö]", "o"):gsub("[ùúûü]","u"):gsub("ÿ","y")
       :gsub("œ","oe"):gsub("æ","ae")
       :gsub("À","A"):gsub("Â","A"):gsub("Ä","A"):gsub("É","E"):gsub("È","E"):gsub("Ê","E"):gsub("Ë","E")
       :gsub("Î","I"):gsub("Ï","I"):gsub("Ô","O"):gsub("Ö","O"):gsub("Ù","U"):gsub("Û","U"):gsub("Ü","U")
       :gsub("Œ","OE"):gsub("Æ","AE"):gsub("’","'")
  return s
end
local function norm(s)
  s = stripAccents(s or ""):lower()
  s = s:gsub("%s+", " ")
  return s
end

-- Resolve sayaad key from preference
local function ChooseSayaadKey()
  -- if user picked "incubus", use the "Sayaad" pack (Pet_Sayaad.lua)
  -- if user picked "succubus", use the "Succubus" pack
  return (DB.sayaad_form == "incubus") and "Sayaad" or "Succubus"
end

-- Treat Succubus/Succube and Incubus/Sayaad as unified family → then resolve by preference
local FAMILY_TO_KEY_NORM = {
  -- Imp
  ["imp"]                = "Imp",
  ["diablotin"]          = "Imp",

  -- Voidwalker
  ["voidwalker"]         = "Voidwalker",
  ["marcheur du vide"]   = "Voidwalker",

  -- Felhunter
  ["felhunter"]          = "Felhunter",
  ["chasseur corrompu"]  = "Felhunter",

  -- Sayaad family (unified)
  ["succubus"]           = "SAYAAD_FORM",
  ["succube"]            = "SAYAAD_FORM",
  ["incubus"]            = "SAYAAD_FORM",
  ["sayaad"]             = "SAYAAD_FORM",

  -- Felguard + variants
  ["felguard"]           = "Felguard",
  ["gangregarde"]        = "Felguard",
  ["wrathguard"]         = "Felguard",
  ["garde funeste"]      = "Felguard",
  ["garde-funeste"]      = "Felguard",
}

local function DetectActivePetKey()
  if UnitExists("pet") and UnitIsUnit("pet", "playerpet") then
    local family = UnitCreatureFamily("pet")
    if family and family ~= "" then
      local key = FAMILY_TO_KEY_NORM[norm(family)]
      if key then
        return (key == "SAYAAD_FORM") and ChooseSayaadKey() or key
      end
    end
    -- fallback: try pet name too
    local pname = UnitName("pet")
    if pname and pname ~= "" then
      local key2 = FAMILY_TO_KEY_NORM[norm(pname)]
      if key2 then
        return (key2 == "SAYAAD_FORM") and ChooseSayaadKey() or key2
      end
    end
  end
  return nil
end

-- ====== Cooldown ======
local _lastSpeakAt = 0
local function _canSpeak()
  local now = GetTime()
  local cd = DB.cooldown or 12
  if (now - _lastSpeakAt) >= cd then
    _lastSpeakAt = now
    return true
  end
  return false
end
SRPWL.CanSpeak = _canSpeak

-- ====== Localized Action Labels ======
local ACTION_LABELS_EN = {
  MountSummoned="Mount summoned", PotionUsed="Potion used", HealthstoneUsed="Healthstone used",
  SoulstoneApplied="Soulstone applied", HearthstoneUsed="Hearthstone used", SummonStoneUsed="Summoning stone",
  PortalUsed="Portal used", BuffReceived="Buff received", GroupInvite="Group invite",
  GroupJoined="Group joined", GroupLeft="Group left", TeammateAlmostDead="Ally critical",
  TeammateDead="Ally dead", RaidWipe="Raid wipe", LootRollWon="Loot won", LootRollLost="Loot lost",
  QuestCompleted="Quest completed", CraftingStarted="Crafting started", CraftingCompleted="Crafting finished",
  SpellCastMajor="Major spell cast", GatheringHerb="Herbalism", GatheringMine="Mining",
  FishingStarted="Fishing started", FishingCatch="Fish caught", GatheringSkin="Skinning",
  GatheringLootChest="Chest looted", GatheringQuestItem="Quest item looted", OpeningCorpseLoot="Corpse looted",
  RepairingGear="Repair", UsingVendor="Vendor", EatingDrinking="Eat/Drink", CookingStarted="Cooking",
  InnResting="Inn resting", BankUsed="Bank", MailboxUsed="Mailbox", AuctionHouseUsed="Auction House",
  TransmogUsed="Transmog", FlightPathTaken="Flight path", DungeonQueueJoin="Dungeon queue",
  ReadyCheck="Ready check", MapOpened="Map opened", PetSummoned="Pet summoned", PetResummoned="Pet resummoned",
  PetSacrificed="Pet sacrificed", BossKill="Boss defeated", EpicLoot="Epic loot", LevelUp="Level up",
  ZoneDiscovered="Zone discovered", Event_GoldReceived="Gold received",
  -- Emotes
  Emote_Hi="Hi", Emote_Love="Love", Emote_Dance="Dance", Emote_Sleep="Sleep", Emote_Pet="Pet",
  Emote_Sit="Sit", Emote_Yes="Yes", Emote_No="No", Emote_Cheer="Cheer", Emote_Clap="Clap", Emote_Thank="Thank",
  Emote_WaveKiss="Blow a kiss", Emote_Rude="Rude", Emote_Bow="Bow", Emote_Kneel="Kneel",
  Emote_Point="Point", Emote_Wave="Wave", Emote_Salute="Salute", Emote_Laugh="Laugh", Emote_Cry="Cry",
  Emote_Hug="Hug", Emote_Pat="Pat", Emote_Shrug="Shrug", Emote_Roar="Roar", Emote_Wink="Wink", Emote_Whistle="Whistle",
  -- NEW
  Emote_Agree="Agree", Trade="Trade",
  Stunned="Stunned", Sheeped="Sheeped", Silenced="Silenced", Traped="Trapped", Feared="Feared",
  Zone_ExileReach="Exile's Reach",
}
local ACTION_LABELS_FR = {
  MountSummoned="Invocation de monture", PotionUsed="Potion utilisée", HealthstoneUsed="Pierre de soin utilisée",
  SoulstoneApplied="Pierre d’âme appliquée", HearthstoneUsed="Pierre de foyer utilisée", SummonStoneUsed="Pierre d’invocation",
  PortalUsed="Portail utilisé", BuffReceived="Amélioration reçue", GroupInvite="Invitation de groupe",
  GroupJoined="Groupe rejoint", GroupLeft="Groupe quitté", TeammateAlmostDead="Allié en danger",
  TeammateDead="Allié mort", RaidWipe="Wipe du raid", LootRollWon="Jet de butin gagné",
  LootRollLost="Jet de butin perdu", QuestCompleted="Quête terminée", CraftingStarted="Fabrication commencée",
  CraftingCompleted="Fabrication terminée", SpellCastMajor="Sort majeur lancé", GatheringHerb="Herboristerie",
  GatheringMine="Minage", FishingStarted="Pêche commencée", FishingCatch="Poisson pêché", GatheringSkin="Dépeçage",
  GatheringLootChest="Coffre fouillé", GatheringQuestItem="Objet de quête récupéré", OpeningCorpseLoot="Butin sur cadavre",
  RepairingGear="Réparation", UsingVendor="Marchand", EatingDrinking="Manger/Boire", CookingStarted="Cuisine",
  InnResting="Repos à l’auberge", BankUsed="Banque", MailboxUsed="Boîte aux lettres", AuctionHouseUsed="Hôtel des ventes",
  TransmogUsed="Transmogrification", FlightPathTaken="Maître de vol", DungeonQueueJoin="File donjon",
  ReadyCheck="Vérif. des prêts", MapOpened="Carte ouverte", PetSummoned="Familier invoqué", PetResummoned="Familier réinvoqué",
  PetSacrificed="Familier sacrifié", BossKill="Boss vaincu", EpicLoot="Butin épique", LevelUp="Niveau gagné",
  ZoneDiscovered="Zone découverte", Event_GoldReceived="Or reçu",
  -- Emotes
  Emote_Hi="Salut", Emote_Love="Amour", Emote_Dance="Danse", Emote_Sleep="Sommeil", Emote_Pet="Caresse",
  Emote_Sit="Assis", Emote_Yes="Oui", Emote_No="Non", Emote_Cheer="Acclame", Emote_Clap="Applaudit", Emote_Thank="Remercie",
  Emote_WaveKiss="Envoie un baiser", Emote_Rude="Geste grossier", Emote_Bow="S’incline", Emote_Kneel="S’agenouille",
  Emote_Point="Montre du doigt", Emote_Wave="Fait signe", Emote_Salute="Salue", Emote_Laugh="Rit", Emote_Cry="Pleure",
  Emote_Hug="Câlin", Emote_Pat="Tape dans le dos", Emote_Shrug="Hausse les épaules", Emote_Roar="Rugit",
  Emote_Wink="Clin d’œil", Emote_Whistle="Siffle",
  -- NEW
  Emote_Agree="D’accord", Trade="Échange",
  Stunned="Étourdi", Sheeped="Métamorphosé", Silenced="Réduit au silence", Traped="Piégé", Feared="Pris de peur",
  Zone_ExileReach="Confins de l’Exil",
}

local function TitleCaseWords(s)
  return (s:gsub("(%a)([%w_']*)", function(a,b) return string.upper(a)..b end))
end

local function PrettyFromPrefix(eventKey, prefix, fallback)
  local tail = eventKey:sub(#prefix + 1)
  tail = tail:gsub("^_", ""):gsub("_", " ")
  tail = TitleCaseWords(tail)
  return (#tail > 0) and tail or fallback
end

local function LocalizedActionLabel(eventKey)
  local loc = GetLocale and GetLocale() or "enUS"
  local T = (loc == "frFR") and ACTION_LABELS_FR or ACTION_LABELS_EN
  local label = T[eventKey]
  if not label then
    if eventKey:find("^Zone_") then
      label = PrettyFromPrefix(eventKey,"Zone_", (loc=="frFR") and "Zone" or "Zone")
    elseif eventKey:find("^Raid_") then
      label = PrettyFromPrefix(eventKey,"Raid_", (loc=="frFR") and "Raid" or "Raid")
    else
      label = TitleCaseWords(eventKey:gsub("_"," "))
    end
  end
  return "< "..label.." >"
end

-- ====== Chat icon selection (Cartoon/Realistic) ======
local ART_PATH = "Interface\\AddOns\\" .. (ADDON_NAME or "SleekRP_WarlockPets") .. "\\Art\\"

local CHAT_ICONS_CARTOON = {
  succubus   = ART_PATH .. "Icon_Succubus.tga",
  felguard   = ART_PATH .. "Icon_Felguard.tga",
  voidwalker = ART_PATH .. "Icon_Voidwalker.tga",
  imp        = ART_PATH .. "Icon_Imp.tga",
  felhunter  = ART_PATH .. "Icon_Felhunter.tga",
  sayaad     = ART_PATH .. "Icon_Sayaad.tga",   -- Incubus
}

local CHAT_ICONS_REAL = {
  succubus   = ART_PATH .. "Icon_Succubus_02.tga",
  felguard   = ART_PATH .. "Icon_Felguard_02.tga",
  voidwalker = ART_PATH .. "Icon_Voidwalker_02.tga",
  imp        = ART_PATH .. "Icon_Imp_02.tga",
  felhunter  = ART_PATH .. "Icon_Felhunter_02.tga",
  sayaad     = ART_PATH .. "Icon_Sayaad_02.tga", -- Incubus
}

local CHAT_FALLBACKS = {
  imp        = 136172,
  voidwalker = 136221,
  felhunter  = 136217,
  succubus   = 136220,
  sayaad     = 4641600, -- Incubus
  felguard   = 136216,
}

local function ToCanonForChat(petKey)
  if not petKey then return nil end
  local k = tostring(petKey):lower()
  if k == "sayaad" or k == "incubus" then return "sayaad" end
  if k == "succubus" then return "succubus" end
  if k == "voidwalker" or k == "imp" or k == "felhunter" or k == "felguard" then return k end
  if k == "wrathguard" then return "felguard" end
  return k
end

function SRPWL.GetChatIconFor(petKey)
  local canon = ToCanonForChat(petKey)
  local styleTable = (DB.portrait_style == "realistic") and CHAT_ICONS_REAL or CHAT_ICONS_CARTOON
  if canon and styleTable[canon] then return styleTable[canon] end
  if canon and CHAT_FALLBACKS[canon] then return CHAT_FALLBACKS[canon] end
  return 136197 -- Question mark
end

-- ====== No-repeat picker ======
local _lastLineByKey = {}
local function pickLineNoRepeat(lines, evKey)
  if not lines or #lines == 0 then return nil end
  local choice
  if #lines == 1 then
    choice = lines[1]
  else
    local tries = 4
    repeat
      choice = lines[math.random(#lines)]
      tries = tries - 1
    until choice ~= _lastLineByKey[evKey] or tries <= 0
  end
  _lastLineByKey[evKey] = choice
  return choice
end

-- ====== Chat out ======
local GOLD = "|cffffd100"
local PALE_VIOLET = "|cffdec9ff"
local RESET = "|r"

local function BuildPetIconTag(icon)
  if not icon then return "" end
  if type(icon) == "number" then
    return ("|T%d:16:16:0:0|t "):format(icon)
  elseif type(icon) == "string" and icon ~= "" then
    return ("|T%s:16:16:0:0|t "):format(icon)
  end
  return ""
end

function SRPWL.ChatOut(actionLabel, petName, text, icon)
  local iconTag = BuildPetIconTag(icon)
  local msg = string.format("%s%s%s %s- %s%s%s : %s%s",
    iconTag,
    GOLD, actionLabel, RESET,
    PALE_VIOLET, (petName or "Pet"), RESET,
    PALE_VIOLET, (text or ""), RESET
  )
  if DEFAULT_CHAT_FRAME and DEFAULT_CHAT_FRAME.AddMessage then
    DEFAULT_CHAT_FRAME:AddMessage(msg)
  else
    print(msg)
  end
end

-- ====== API: TrySpeak ======
function SRPWL.TrySpeak(eventKey)
  if not eventKey then return end
  PET_KEY_ACTIVE = DetectActivePetKey()
  local pet = SRPWL.GetPet(PET_KEY_ACTIVE)

  if not pet then
    if DB.debug then
      print(string.format("|cffa9a9ff[SRP]|r No pet registered for key '%s'.", tostring(PET_KEY_ACTIVE)))
    end
    return
  end
  if not _canSpeak() then return end

  local lines = pet.dialogues[eventKey]
  local text = pickLineNoRepeat(lines, eventKey)
  if not text then return end

  local label = LocalizedActionLabel(eventKey)
  local petName = (UnitExists("pet") and UnitName("pet")) or pet.pretty or pet.key

  -- Talking UI: do NOT pass an icon (PetTalking choisit en Cartoon/Realistic)
  if SRPWL.ShowTalking then
    SRPWL.ShowTalking(pet.key, petName, label, text, nil)
  end

  -- Chat: choose icon according to portrait_style
  local chatIcon = SRPWL.GetChatIconFor(pet.key)
  SRPWL.ChatOut(label, petName, text, chatIcon)

  if DB.enable_audio and SRPWL.AudioPlayFor then
    SRPWL.AudioPlayFor(eventKey, pet.key, text)
  end
end

-- ===== Events ======
local _loginAt = 0
local f = CreateFrame("Frame")
f:RegisterEvent("PLAYER_LOGIN")
f:RegisterEvent("UNIT_PET")
f._lastPetGUID = nil

f:SetScript("OnEvent", function(_, ev, ...)
  if ev == "PLAYER_LOGIN" then
    PET_KEY_ACTIVE = DetectActivePetKey()
    SleekRP_WLP_DB.use_talking_style = true
    _loginAt = GetTime()
    f._lastPetGUID = UnitGUID("pet")

  elseif ev == "UNIT_PET" then
    local unit = ...
    if unit == "player" then
      local afterLogin = (GetTime() - (_loginAt or 0)) > 5
      C_Timer.After(0.25, function()
        PET_KEY_ACTIVE = DetectActivePetKey()
        local g = UnitGUID("pet")
        if afterLogin then
          if g and not f._lastPetGUID then
            SRPWL.TrySpeak("PetSummoned")
          elseif g and f._lastPetGUID and g ~= f._lastPetGUID then
            SRPWL.TrySpeak("PetResummoned")
          end
        end
        f._lastPetGUID = g
      end)
    end
  end
end)

-- ===== Slash =====
SLASH_SLEEKRP1 = "/srp"
SlashCmdList["SLEEKRP"] = function(msg)
  local cmd, a, b = msg:match("^(%S+)%s*(%S*)%s*(%S*)")
  cmd = cmd and cmd:lower() or ""

  if cmd == "test" then
    local eventKey = (a ~= "" and a) or "PetSummoned"
    local petKey = (b ~= "" and b) or PET_KEY_ACTIVE
    local pet = SRPWL.GetPet(petKey)
    if not pet then
      print("|cffa9a9ff[SRP]|r Test: unknown pet key.")
      return
    end
    local lines = pet.dialogues[eventKey]
    local function pickLineLocal(t) if t and #t>0 then return t[math.random(#t)] end end
    local text = pickLineLocal(lines) or "(no line)"
    local label = LocalizedActionLabel(eventKey)
    local petName = (UnitExists("pet") and UnitName("pet")) or (pet.pretty or pet.key)

    -- Talking UI: no icon override
    if SRPWL.ShowTalking then
      SRPWL.ShowTalking(pet.key, petName, label, text, nil)
    end
    -- Chat: icon by style
    local chatIcon = SRPWL.GetChatIconFor(pet.key)
    SRPWL.ChatOut(label, petName, text, chatIcon)

    if DB.enable_audio and SRPWL.AudioPlayFor and lines and #lines > 0 then
      SRPWL.AudioPlayFor(eventKey, pet.key, text)
    end
    print("|cffa9a9ff[SRP]|r Test:", (petKey or "?"), "["..eventKey.."] ->", text)
    return
  end

  print("|cffa9a9ff[SRP]|r Usage:")
  print("  /srp test [EventKey] [PetKey]")
end
