VoiceOver = VoiceOver or {}
setfenv(1, VoiceOver)
SoundQueue = SoundQueue or {}

local MAX_SOUND_DURATION = 7.0
local SOUND_CHANNEL = "Master" -- Asegura que no se silencien otros canales
local soundCooldown = false    -- Bloqueo temporal para evitar duplicados

-- Midnight compatibility check
local hasVignetteAPI = C_VignetteInfo and C_VignetteInfo.GetVignettes and C_VignetteInfo.GetVignetteInfo
if not hasVignetteAPI then
    Debug:Print(Utils:ColorizeText("Vignette API not available - RareTracker disabled", RED_FONT_COLOR_CODE), "RareTracker")
    return
end

-- Tabla para rastrear raros ya reproducidos (evita duplicados en la sesión)
local rareAudioPlayed = {}

-- Helper function to check if we're in an instance (where secret values apply)
-- Also includes banks where rare detection is not useful
local function IsInRestrictedArea()
    local inInstance, instanceType = IsInInstance()
    -- Dungeons, raids, scenarios - rare portraits not useful here
    if inInstance and (instanceType == "party" or instanceType == "raid" or instanceType == "scenario") then
        return true
    end
    
    -- Check if player is at a bank (mailbox areas often near banks)
    if BankFrame and BankFrame:IsShown() then
        return true
    end
    
    -- Check if secret restrictions are active
    if C_RestrictedActions and C_RestrictedActions.IsAddOnRestrictionActive then
        return C_RestrictedActions.IsAddOnRestrictionActive(Enum.AddOnRestrictionType.Map)
    end
    return false
end

-- Helper function to safely extract ID and type from GUID (handles secret values)
-- Returns: id, isGameObject
local function SafeGetIDFromGUID(guid)
    if not guid then return nil, false end

    -- Check if the value is secret
    if issecretvalue and issecretvalue(guid) then
        return nil, false
    end

    -- Detect if it's a GameObject or Creature
    local isGameObject = guid:match("^GameObject") ~= nil
    
    -- Try to extract ID
    local success, id = pcall(function()
        return tonumber(guid:match("-(%d+)-%x+$"))
    end)

    if not success then
        return nil, false
    end

    return id, isGameObject
end

-- Variables para el estado del módulo
local isRareAnnounceActive = false
local isRareAnnounceDebugEnabled = false

-- Función para imprimir mensajes de depuración en el chat
local function RareAnnounceDebugPrint(message)
    if isRareAnnounceDebugEnabled then
        DEFAULT_CHAT_FRAME:AddMessage("|cFF00FF00[Rare Announce Debug]|r " .. message)
    end
end

local RED = "|cFFFF0000"
local GREEN = "|cFF00FF00"
local RESET = "|r"

-- DebugPrint(RED .. "RareTracker module loaded" .. RESET)

local frame = CreateFrame("Frame")
frame:RegisterEvent("VIGNETTE_MINIMAP_UPDATED")

local playedRares = {}

-- Icon ID para raros (skull icon)
local RARE_ICON_ID = 236192 -- Skull icon from vignettes

-- Función para obtener los IDs de loot del rare o GameObject
local function GetRareLootItems(objectID, isGameObject)
    local db = isGameObject and MidnightGameObjectDB or MidnightLootDB
    
    if not db or not db[objectID] then
        return nil
    end
    
    local data = db[objectID]
    
    if data.loot and #data.loot > 0 then
        return data.loot
    end
    
    return nil
end

frame:SetScript("OnEvent", function(self, event, ...)
    if not isRareAnnounceActive then
        return
    end

    if event == "VIGNETTE_MINIMAP_UPDATED" and not soundCooldown then
        -- Defensive check for API availability
        if not C_VignetteInfo or not C_VignetteInfo.GetVignettes then
            return
        end

        -- Check if we're in a restricted area where GUIDs/names will be secret
        local inRestrictedArea = IsInRestrictedArea()
        if inRestrictedArea then
            return
        end

        local vignettes = C_VignetteInfo.GetVignettes()
        if not vignettes then return end

        for _, vignetteGUID in pairs(vignettes) do
            local vignetteInfo = C_VignetteInfo.GetVignetteInfo(vignetteGUID)
            if vignetteInfo then
                -- Future-proof: check for VignetteKill or similar rare indicators
                local isRare = vignetteInfo.atlasName == "VignetteKill" or
                               vignetteInfo.atlasName == "VignetteKillElite" or
                               (vignetteInfo.type and vignetteInfo.type == Enum.VignetteType.Normal)

                if isRare then
                    -- Safely extract ID and type (handles secret values)
                    local objectID, isGameObject = SafeGetIDFromGUID(vignetteInfo.objectGUID)

                    if objectID and not playedRares[objectID] then
                        playedRares[objectID] = true

                        -- Safely get rare name (may be secret in instances)
                        local rareName = "Rare Detected"
                        if vignetteInfo.name and not (issecretvalue and issecretvalue(vignetteInfo.name)) then
                            rareName = vignetteInfo.name
                        end

                        -- Add to SoundQueue using DialogueAdapter pattern (like Cielonautica)
                        QueueRareDialogue(rareName, objectID, isGameObject)
                    end
                end
            end
        end
    end
end)

-- ============================================================
-- Queue Rare Dialogue (Similar a Cielonáutica en DialogueAdapter)
-- ============================================================
function QueueRareDialogue(rareName, objectID, isGameObject)
    -- Evitar duplicados en la sesión actual
    if rareAudioPlayed[objectID] then
        return
    end

    -- Verificar que no esté en cooldown global
    if soundCooldown then
        return
    end

    -- Marcar como reproducido
    rareAudioPlayed[objectID] = true
    soundCooldown = true

    -- Obtener items de loot (tanto para criaturas como GameObjects)
    local lootItems = GetRareLootItems(objectID, isGameObject)

    -- Seleccionar archivo de sonido aleatorio
    local fileName
    if isGameObject then
        -- GameObjects: 3 variantes (Generic_Object, Generic_Object2, Generic_Object3)
        local randomVariant = math.random(1, 3)
        if randomVariant == 1 then
            fileName = "Rare_Detected_Generic_Object"
        else
            fileName = "Rare_Detected_Generic_Object" .. randomVariant
        end
    else
        -- Criaturas raras: 3 variantes (Generic, Generic2, Generic3)
        local randomVariant = math.random(1, 3)
        if randomVariant == 1 then
            fileName = "Rare_Detected_Generic"
        else
            fileName = "Rare_Detected_Generic" .. randomVariant
        end
    end

    -- Crear soundData usando el patrón de DialogueAdapter (como Cielonáutica)
    local soundData = {
        event = Enums.SoundEvent.Rare, -- Usar evento Rare para carpeta rares
        name = rareName, -- Título: nombre del rare
        text = isGameObject and "A world object has been detected: " .. rareName or "A rare enemy has been detected: " .. rareName,
        title = lootItems and "You can obtain these items:" or (isGameObject and "World Object" or "Rare enemy detected"),
        fileName = fileName, -- Archivo aleatorio para GameObjects (1-3)
        creatureID = not isGameObject and objectID or nil, -- Solo para criaturas
        isGameObject = isGameObject, -- Flag para indicar si es un GameObject
        gameObjectID = isGameObject and objectID or nil, -- ID del GameObject
        displayID = nil, -- No tenemos displayID
        lootItems = lootItems, -- Array de item IDs para mostrar iconos
        keepOpen = true, -- Mantener abierto hasta que llegue otro sonido
        iconID = isGameObject and 1542847 or nil, -- Icono de chest/tesoro para GameObjects
    }

    -- Verificar que DataModules y SoundQueue existan
    if not DataModules or not DataModules.PrepareSound then
        soundCooldown = false
        return
    end

    if not SoundQueue or not SoundQueue.AddSoundToQueue then
        soundCooldown = false
        return
    end

    -- Preparar el sonido (esto busca el archivo y establece filePath, length, etc.)
    local soundExists = DataModules:PrepareSound(soundData)

    if soundExists then
        -- Usar RareTruePortrait en lugar de SoundQueue
        if RareTruePortrait then
            RareTruePortrait:Show(soundData)
        end

        -- Desbloquear después del audio
        C_Timer.After((soundData.length or 5) + 2, function()
            soundCooldown = false
        end)
    else
        soundCooldown = false
    end
end

function ResetPlayedRares()
    playedRares = {}
    rareAudioPlayed = {}
end

-- Función para activar el módulo
function ActivateRareAnnounce()
    isRareAnnounceActive = true
    isRareAnnounceDebugEnabled = Addon.db.profile.RareAnnounceDebugEnabled
end

-- Función para desactivar el módulo
function DeactivateRareAnnounce()
    isRareAnnounceActive = false
    isRareAnnounceDebugEnabled = false
end

-- Exponer las funciones de activación/desactivación
VoiceOver.RareAnnounce = VoiceOver.RareAnnounce or {}
VoiceOver.RareAnnounce.Activate = ActivateRareAnnounce
VoiceOver.RareAnnounce.Deactivate = DeactivateRareAnnounce

-- Auto-activar el módulo cuando el addon se carga completamente (si está habilitado en opciones)
hooksecurefunc(Addon, "OnInitialize", function()
    C_Timer.After(1, function()
        -- Solo activar si está habilitado en las opciones
        if Addon.db.profile.RareAnnounceEnabled then
            ActivateRareAnnounce()
        end
    end)
end)

-- ============================================================
-- SLASH COMMANDS para control f
