-- ============================================================
-- Asylum Compagnon — Core.lua
-- Initialisation, variables sauvegardées, bouton minimap,
-- événements (équipement/talents/or/sacs/groupe), commandes.
-- ============================================================

local ADDON_NAME, NS = ...

-- Couleur d'accent (violet moderne) et icône (fileID vérifié)
NS.ACCENT = "a78bfa"
NS.ICON_ID = 254109 -- achievement_dungeon_ulduarraid_irongolem_01

-- Consommables suivis dans le menu Inventaire.
-- ids = tous les itemID de l'objet (les paliers de qualité ont parfois
-- des ID distincts : on additionne). Le 1er ID sert de clé + d'icône.
-- Le nom affiché en jeu est localisé automatiquement (FR sur client FR).
NS.TRACKED_ITEMS = {
    -- Flacons (EN: Flask of the Shattered Sun / Magisters / Blood Knights)
    { ids = { 241326 },         fallback = "Flacon du Soleil brisé" },
    { ids = { 241322, 241323 }, fallback = "Flacon des magistères" },
    { ids = { 241324, 241325 }, fallback = "Flacon des chevaliers de sang" },
    -- Potions (EN: Light's Potential / Potion of Recklessness)
    { ids = { 241309, 241308 }, fallback = "Potentiel de la Lumière" },
    { ids = { 241288, 241289 }, fallback = "Potion de témérité" },
    -- Festins (EN: Hearty Harandar Celebration / Royal Roast / Tasty Smoked Tetra)
    { ids = { 266996 },         fallback = "Célébration d'Harandar copieuse" },
    { ids = { 242747 },         fallback = "Rôti royal copieux" },
    { ids = { 242750 },         fallback = "Tétra fumé savoureux copieux" },
    -- Huiles d'arme (EN: Thalassian Phoenix Oil / Oil of Dawn / Smuggler's Enchanted Edge)
    { ids = { 243733, 243734 }, fallback = "Huile de phénix thalassienne" },
    { ids = { 243735, 243736 }, fallback = "Huile de l'aube" },
    { ids = { 243737, 243738 }, fallback = "Tranchant enchanté de contrebandier" },
}

-- Sorts d'interruption → cooldown de base en secondes.
-- Table éditable : ajoute ici tout spellID manquant (les variants
-- d'un même kick ont des IDs différents, ex. Commandement du démon).
NS.INTERRUPTS = {
    [6552]   = 15, -- Guerrier : Volée de coups (Pummel)
    [96231]  = 15, -- Paladin : Réprimandes (Rebuke)
    [31935]  = 15, -- Paladin Prot : Bouclier du vengeur
    [147362] = 24, -- Chasseur : Tir de contre (Counter Shot)
    [187707] = 15, -- Chasseur Survie : Musellement (Muzzle)
    [1766]   = 15, -- Voleur : Coup de pied (Kick)
    [15487]  = 45, -- Prêtre Ombre : Silence
    [47528]  = 15, -- CdM : Gel de l'esprit (Mind Freeze)
    [221562] = 45, -- CdM Sang : Asphyxie (interrompt via étourdissement)
    [47476]  = 60, -- CdM : Strangulation (si talentée)
    [57994]  = 12, -- Chaman : Cisaillement des vents (Wind Shear)
    [2139]   = 24, -- Mage : Contresort (Counterspell)
    [19647]  = 24, -- Démoniste : Verrou de sort (chasseur corrompu)
    [119910] = 24, -- Démoniste : Verrou de sort (Commandement du démon)
    [132409] = 24, -- Démoniste : Verrou de sort (pacte de sacrifice)
    [89766]  = 30, -- Démoniste : Lancer de hache (gangregarde)
    [119914] = 30, -- Démoniste : Lancer de hache (Commandement du démon)
    [116705] = 15, -- Moine : Frappe du bras-lance (Spear Hand Strike)
    [106839] = 15, -- Druide : Coup de crâne (Skull Bash)
    [78675]  = 60, -- Druide Équilibre : Rayon solaire (Solar Beam)
    [183752] = 15, -- Chasseur de démons : Perturbation (Disrupt)
    [351338] = 40, -- Évocateur : Étouffement (Quell)
}

local atan2 = math.atan2 or function(y, x) return math.atan(y, x) end

local DEFAULTS = {
    minimapPos  = 212,  -- angle (degrés) du bouton autour de la minimap
    kickOverlay = true, -- encadré des kicks visible dans l'interface
    kickBgAlpha = 0.6,  -- opacité du fond de l'encadré des kicks
    alertChat   = true, -- alerte chat quand une ressource tombe à 0
    alertRaid   = true, -- alerte au centre de l'écran (style raid warning)
    alertSound  = true, -- alerte sonore
}

-- ---------- Buffs & auras suivis (tables éditables) ----------
-- Astuce : /asylum auras liste les spellID de tes buffs actuels,
-- pratique pour compléter ces tables.

-- Auras de flacons (Midnight — spellID de l'aura, pas de l'objet)
NS.FLASK_AURAS = {
    [1230878] = true, -- Flask of the Shattered Sun
    [1230876] = true, -- Flask of the Magisters
    [1230877] = true, -- Flask of the Blood Knights
    [1235110] = true, -- variante de qualité
    [1235111] = true, -- variante de qualité
}

-- Auras « Bien nourri » (Midnight)
NS.FOOD_AURAS = {
    [1278929] = true, -- Hearty Well Fed (festins Hearty)
    [461957]  = true, -- Well Fed (générique récent)
}

-- Buffs de groupe par classe : colonne affichée si la classe est
-- présente dans le groupe
NS.RAID_BUFFS = {
    { class = "PRIEST",  label = "Robu.",   ids = { [21562]  = true } }, -- Mot de pouvoir : Robustesse
    { class = "MAGE",    label = "Int.",    ids = { [1459]   = true } }, -- Intelligence des arcanes
    { class = "DRUID",   label = "Sauvage", ids = { [1126]   = true } }, -- Marque du fauve
    { class = "WARRIOR", label = "Cri",     ids = { [6673]   = true } }, -- Cri de guerre
    { class = "EVOKER",  label = "Bronze",  ids = { [381748] = true } }, -- Bénédiction du bronze
    { class = "SHAMAN",  label = "Furie",   ids = { [462854] = true } }, -- Furie-des-cieux
    { class = "PALADIN", label = "Aura",    ids = { [465] = true, [32223] = true, [317920] = true } }, -- Auras
}

-- Alerte quand un consommable suivi tombe à 0 (une fois par session/objet)
-- Chaque canal (chat / écran / son) est activable dans le menu Alertes.
local depletedNotified = {}
function NS.NotifyDepleted(itemID)
    if depletedNotified[itemID] then return end
    depletedNotified[itemID] = true
    local db = NS.db or {}
    if db.alertChat == false and db.alertRaid == false and db.alertSound == false then return end
    local function announce(name)
        local label = name or ("objet " .. itemID)
        if db.alertChat ~= false then
            NS.Msg(("|cffea4850stock épuisé :|r %s"):format(label))
        end
        if db.alertRaid ~= false and RaidNotice_AddMessage and RaidWarningFrame then
            pcall(RaidNotice_AddMessage, RaidWarningFrame,
                ("Stock épuisé : %s"):format(label),
                (ChatTypeInfo and ChatTypeInfo["RAID_WARNING"]) or { r = 1, g = 0.28, b = 0.31 })
        end
        if db.alertSound ~= false and SOUNDKIT and PlaySound then
            PlaySound(SOUNDKIT.RAID_WARNING)
        end
    end
    if Item and Item.CreateFromItemID then
        local it = Item:CreateFromItemID(itemID)
        it:ContinueOnItemLoad(function() announce(it:GetItemName()) end)
    else
        announce(nil)
    end
end

local function Msg(text)
    print(("|cff%sAsylum Compagnon|r · %s"):format(NS.ACCENT, text))
end
NS.Msg = Msg

-- ---------- SavedVariables ----------
local function InitDB()
    AsylumCompagnonDB = AsylumCompagnonDB or {}
    for k, v in pairs(DEFAULTS) do
        if AsylumCompagnonDB[k] == nil then AsylumCompagnonDB[k] = v end
    end
    if type(AsylumCompagnonDB.peers) ~= "table" then AsylumCompagnonDB.peers = {} end
    NS.db = AsylumCompagnonDB

    -- données par personnage (mémoire des objets déjà possédés)
    AsylumCompagnonCharDB = AsylumCompagnonCharDB or {}
    if type(AsylumCompagnonCharDB.itemsSeen) ~= "table" then AsylumCompagnonCharDB.itemsSeen = {} end
    NS.chardb = AsylumCompagnonCharDB
end

-- ---------- Bouton minimap ----------
local button

local function UpdateButtonPosition()
    if not button then return end
    local angle  = math.rad(NS.db.minimapPos or DEFAULTS.minimapPos)
    local radius = (Minimap:GetWidth() / 2) + 5
    button:ClearAllPoints()
    button:SetPoint("CENTER", Minimap, "CENTER",
        math.cos(angle) * radius, math.sin(angle) * radius)
end
NS.UpdateMinimapButton = UpdateButtonPosition

local function OnDragUpdate()
    local mx, my = Minimap:GetCenter()
    local cx, cy = GetCursorPosition()
    local scale  = Minimap:GetEffectiveScale()
    cx, cy = cx / scale, cy / scale
    NS.db.minimapPos = math.deg(atan2(cy - my, cx - mx)) % 360
    UpdateButtonPosition()
end

local function CreateMinimapButton()
    if button then return end
    button = CreateFrame("Button", "AsylumCompagnonMinimapButton", Minimap)
    button:SetSize(31, 31)
    button:SetFrameStrata("MEDIUM")
    button:SetFrameLevel(8)
    button:RegisterForClicks("LeftButtonUp")
    button:RegisterForDrag("LeftButton")

    local ring = button:CreateTexture(nil, "BACKGROUND", nil, -2)
    ring:SetTexture("Interface\\Buttons\\WHITE8x8")
    ring:SetAllPoints()
    ring:SetVertexColor(1, 1, 1, 0.15)
    local ringMask = button:CreateMaskTexture()
    ringMask:SetTexture("Interface\\CharacterFrame\\TempPortraitAlphaMask")
    ringMask:SetAllPoints(ring)
    ring:AddMaskTexture(ringMask)

    local disc = button:CreateTexture(nil, "BACKGROUND", nil, -1)
    disc:SetTexture("Interface\\Buttons\\WHITE8x8")
    disc:SetPoint("CENTER")
    disc:SetSize(28, 28)
    disc:SetVertexColor(0.055, 0.06, 0.078, 1)
    local discMask = button:CreateMaskTexture()
    discMask:SetTexture("Interface\\CharacterFrame\\TempPortraitAlphaMask")
    discMask:SetAllPoints(disc)
    disc:AddMaskTexture(discMask)

    local icon = button:CreateTexture(nil, "ARTWORK")
    icon:SetTexture(NS.ICON_ID)
    icon:SetTexCoord(0.07, 0.93, 0.07, 0.93)
    icon:SetPoint("CENTER")
    icon:SetSize(24, 24)
    local iconMask = button:CreateMaskTexture()
    iconMask:SetTexture("Interface\\CharacterFrame\\TempPortraitAlphaMask")
    iconMask:SetAllPoints(icon)
    icon:AddMaskTexture(iconMask)

    button:SetScript("OnEnter", function(self)
        ring:SetVertexColor(0.655, 0.545, 0.98, 1)
        GameTooltip:SetOwner(self, "ANCHOR_LEFT")
        GameTooltip:SetText("Asylum Compagnon", 1, 1, 1)
        GameTooltip:AddLine("Clic gauche : ouvrir / fermer", 0.72, 0.72, 0.78)
        GameTooltip:AddLine("Glisser : déplacer le bouton", 0.72, 0.72, 0.78)
        GameTooltip:Show()
    end)
    button:SetScript("OnLeave", function()
        ring:SetVertexColor(1, 1, 1, 0.15)
        GameTooltip:Hide()
    end)

    button:SetScript("OnMouseDown", function() icon:SetSize(22, 22) end)
    button:SetScript("OnMouseUp", function() icon:SetSize(24, 24) end)
    button:SetScript("OnClick", function() NS.Toggle() end)
    button:SetScript("OnDragStart", function(self)
        self:SetScript("OnUpdate", OnDragUpdate)
    end)
    button:SetScript("OnDragStop", function(self)
        self:SetScript("OnUpdate", nil)
    end)

    UpdateButtonPosition()
end

-- ---------- Mises à jour du profil (anti-spam) ----------
-- rapide (3 s) : équipement / talents / spé
local profileTimer
local function QueueProfileUpdate()
    if profileTimer then profileTimer:Cancel() end
    profileTimer = C_Timer.NewTimer(3, function()
        profileTimer = nil
        if InCombatLockdown and InCombatLockdown() then
            QueueProfileUpdate()
            return
        end
        if NS.UpdateMyProfile then NS.UpdateMyProfile(true) end
    end)
end

-- lente (12 s) : or / contenu des sacs
local invTimer
local function QueueInventoryUpdate()
    if invTimer then return end
    invTimer = C_Timer.NewTimer(12, function()
        invTimer = nil
        if InCombatLockdown and InCombatLockdown() then return end
        if NS.UpdateMyProfile then NS.UpdateMyProfile(true) end
    end)
end

local groupTimer
local function QueueGroupHello()
    if groupTimer then return end
    groupTimer = C_Timer.NewTimer(8, function()
        groupTimer = nil
        if NS.Sync and NS.Sync.available then NS.Sync.BroadcastHello(true) end
    end)
end

-- ---------- Événements ----------
local entered = false
local events = CreateFrame("Frame")
events:RegisterEvent("ADDON_LOADED")
events:RegisterEvent("PLAYER_LOGIN")
events:RegisterEvent("PLAYER_ENTERING_WORLD")
events:RegisterEvent("PLAYER_EQUIPMENT_CHANGED")
events:RegisterEvent("TRAIT_CONFIG_UPDATED")
events:RegisterEvent("PLAYER_SPECIALIZATION_CHANGED")
events:RegisterEvent("GROUP_ROSTER_UPDATE")
events:RegisterEvent("PLAYER_MONEY")
events:RegisterEvent("BAG_UPDATE_DELAYED")
events:SetScript("OnEvent", function(_, event, arg1)
    if event == "ADDON_LOADED" and arg1 == ADDON_NAME then
        InitDB()
        NS.VERSION = (C_AddOns and C_AddOns.GetAddOnMetadata
            and C_AddOns.GetAddOnMetadata(ADDON_NAME, "Version")) or "0.3.0"
        events:UnregisterEvent("ADDON_LOADED")

    elseif event == "PLAYER_LOGIN" then
        CreateMinimapButton()
        Msg(("chargé — |cff%s/asylum|r pour ouvrir, ou clique le bouton autour de la minimap."):format(NS.ACCENT))

    elseif event == "PLAYER_ENTERING_WORLD" then
        if not entered then
            entered = true
            -- petit délai : le temps que talents/équipement soient disponibles
            C_Timer.After(4, function()
                if NS.UpdateMyProfile then NS.UpdateMyProfile(false) end
                if NS.Sync and NS.Sync.available then NS.Sync.BroadcastHello(true) end
            end)
        end

    elseif event == "PLAYER_EQUIPMENT_CHANGED"
        or event == "TRAIT_CONFIG_UPDATED" then
        if entered then QueueProfileUpdate() end

    elseif event == "PLAYER_SPECIALIZATION_CHANGED" then
        if entered and (not arg1 or arg1 == "player") then QueueProfileUpdate() end

    elseif event == "GROUP_ROSTER_UPDATE" then
        if entered then QueueGroupHello() end

    elseif event == "PLAYER_MONEY" or event == "BAG_UPDATE_DELAYED" then
        if entered then QueueInventoryUpdate() end
    end
end)

-- ---------- Commandes slash ----------
SLASH_ASYLUMCOMPAGNON1 = "/asylum"
SlashCmdList.ASYLUMCOMPAGNON = function(msg)
    msg = msg or ""
    local cmd = (msg:match("^(%S*)") or ""):lower()

    if cmd == "" then
        NS.Toggle()
    elseif cmd == "auras" then
        -- liste les spellID de tes buffs (pour compléter les tables)
        Msg("tes buffs actuels :")
        if C_UnitAuras and C_UnitAuras.GetBuffDataByIndex then
            for i = 1, 60 do
                local ok, aura = pcall(C_UnitAuras.GetBuffDataByIndex, "player", i)
                if not ok or not aura then break end
                local sid = aura.spellId
                if sid and not (issecretvalue and issecretvalue(sid)) then
                    print(("   %d — %s"):format(sid, tostring(aura.name)))
                end
            end
        end
    elseif cmd == "sync" then
        if NS.Sync and NS.Sync.available then
            if NS.UpdateMyProfile then NS.UpdateMyProfile(false) end
            NS.Sync.BroadcastHello(true)
            Msg("annonce envoyée au groupe et à la guilde.")
        else
            Msg("synchro indisponible (canal de communication non enregistré).")
        end
    elseif cmd == "reset" then
        for k, v in pairs(DEFAULTS) do NS.db[k] = v end
        NS.db.peers = {}
        NS.db.kickPos = nil
        NS.db.kickScale = nil
        NS.db.uiScale = nil
        NS.db.uiPos = nil
        if _G["AsylumCompagnonFrame"] then _G["AsylumCompagnonFrame"]:SetScale(1) end
        UpdateButtonPosition()
        if NS.Kicks then
            NS.Kicks.ResetPosition()
            NS.Kicks.SetEnabled(true)
            if NS.Kicks.ApplyStyle then NS.Kicks.ApplyStyle() end
        end
        Msg("réglages remis par défaut (liste d'amis vidée).")
    else
        Msg("commandes : |cffffffff/asylum|r ouvrir · |cffffffff/asylum sync|r annoncer · |cffffffff/asylum reset|r")
    end
end

-- ---------- Compartiment d'addons (tiroir de la minimap) ----------
function AsylumCompagnon_OnCompartmentClick()
    NS.Toggle()
end
