setfenv(1, VoiceOver)

local questProgressCache = {}
local isActive = true
local lastMonsterChatTime = 0
local MONSTER_CHAT_SILENCE = 12

-- Definición de colores para el debug
local RED = "|cFFFF0000"
local GREEN = "|cFF00FF00"
local RESET = "|r"

-- Función para manejar los mensajes de depuración
local function debugmodemissionprogress(message)
    if VoiceOver.MissionProgress.DebugMode then
        Debug:Print(message, "MissionProgress Debug")
    end
end

-- Obtener la duración del sonido de los datos
local function GetSoundDuration(questID)
    local soundData = {
        event = Enums.SoundEvent.QuestProgress,
        questID = questID,
    }
    local success = DataModules:PrepareSound(soundData)
    if success then
        return soundData.length
    else
        return 5 -- Duración por defecto de 5 segundos si no se encuentra la duración
    end
end

-- Obtener el ID y el nombre del NPC correspondiente a un Quest ID
local function GetNPCInfoByQuestID(questID)
    local type, id = DataModules:GetQuestLogQuestGiverTypeAndID(questID, true) -- Pasar `true` para usar el segundo valor
    if type and id then
        local name = DataModules:GetObjectName(type, id)
        return id, name
    end
    return nil, "Unknown"
end

local function ShowNPCFrame(questID, questTitle)
    -- ShowNPCFrame solo muestra el retrato, el audio lo maneja PlayQuestProgressSound
end

local function GetQuestProgress(questLogIndex)
    local objectivesCompleted = 0
    local objectivesTotal = 0

    for i = 1, GetNumQuestLeaderBoards(questLogIndex) do
        local text, objectiveType, finished = GetQuestLogLeaderBoard(i, questLogIndex)

        -- Depuración: Imprimir los valores retornados
        debugmodemissionprogress(string.format("Objective %d: text=%s, type=%s, finished=%s", i, tostring(text),
            tostring(objectiveType), tostring(finished)))

        if objectiveType ~= "header" then
            if text then
                local numCompleted, numRequired = string.match(text, "(%d+)/(%d+)")
                if numCompleted and numRequired then
                    numCompleted = tonumber(numCompleted)
                    numRequired = tonumber(numRequired)
                    objectivesCompleted = objectivesCompleted + numCompleted
                    objectivesTotal = objectivesTotal + numRequired
                else
                    -- Si no hay progreso numérico, usar el estado 'finished'
                    if finished then
                        objectivesCompleted = objectivesCompleted + 1
                        objectivesTotal = objectivesTotal + 1
                    else
                        objectivesTotal = objectivesTotal + 1
                    end
                end
            else
                -- Si 'text' es nil, usar el estado 'finished'
                if finished then
                    objectivesCompleted = objectivesCompleted + 1
                    objectivesTotal = objectivesTotal + 1
                else
                    objectivesTotal = objectivesTotal + 1
                end
            end
        end
    end

    if objectivesTotal > 0 then
        return (objectivesCompleted / objectivesTotal) * 100
    else
        return 0
    end
end

local lastPrintTime = 0
local PRINT_INTERVAL = 5 -- Intervalo de tiempo en segundos para evitar impresiones duplicadas

local function PlayQuestProgressSound(questID, questTitle)
    if not isActive then return end

    -- SEGURIDAD: No reproducir audio de progreso (100%) si ya se reprodujo "QuestComplete" recientemente para esta misión.
    -- Esto evita el doble audio cuando recibes un ítem de recompensa.
    if not CanPlayQuestEvent(questID, Enums.SoundEvent.QuestComplete) then
        debugmodemissionprogress("Bloqueando audio de progreso: la misión ya se reprodujo como completada.")
        return
    end

    -- Usar el sistema centralizado para verificar si el evento de progreso ya sonó
    if not CanPlayQuestEvent(questID, Enums.SoundEvent.QuestProgress) then
        debugmodemissionprogress("Audio de progreso ya reproducido recientemente para questID: " .. questID)
        return
    end

    if not questProgressCache[questID] or questProgressCache[questID] ~= "played" then
        debugmodemissionprogress("Intentando reproducir sonido para questID: " .. questID)
        
        -- Obtener información del NPC para el formato específico questID-progress-npcID
        local npcID, npcName = GetNPCInfoByQuestID(questID)
        npcName = npcName or "Unknown"
        
        -- Preparar datos del sonido
        local soundData = {
            event = Enums.SoundEvent.QuestProgress,
            questID = questID,
            name = npcName,
            title = questTitle or "",
            unitGUID = npcID and string.format("Creature-0-0-0-0-%d", npcID) or nil,
            creatureID = npcID,
            unitIsObjectOrItem = false
        }
        
        -- Usar el sistema DataModules para buscar y preparar el sonido
        local success = DataModules:PrepareSound(soundData)
        
        if success then
            debugmodemissionprogress(GREEN .. "Sonido encontrado para questID: " .. questID .. " - Reproduciendo: " .. (soundData.filePath or "desconocido") .. RESET)

            -- Marcar como reproducido en el sistema central ANTES de añadir a la cola
            MarkQuestEventAsPlayed(questID, Enums.SoundEvent.QuestProgress)
            questProgressCache[questID] = "played"

            local function TryEnqueue()
                if (GetTime() - lastMonsterChatTime) < MONSTER_CHAT_SILENCE then
                    C_Timer.After(2, TryEnqueue)
                    return
                end
                SoundQueue:AddSoundToQueue(soundData)
            end

            C_Timer.After(2, TryEnqueue)
        else
            debugmodemissionprogress(RED .. "No se encontró sonido para questID: " .. questID .. RESET)
        end
    end
end

local function OnQuestLogUpdate()
    if not isActive then return end

    local currentTime = time()
    if currentTime - lastPrintTime < PRINT_INTERVAL then
        return
    end
    lastPrintTime = currentTime

    local numEntries = C_QuestLog.GetNumQuestLogEntries()
    for i = 1, numEntries do
        local questInfo = C_QuestLog.GetInfo(i)
        if questInfo and not questInfo.isHeader then
            local title = questInfo.title
            local questID = questInfo.questID
            local questProgress = GetQuestProgress(i)
            if questProgress then
                local previousProgress = questProgressCache[questID] or 0
                if type(previousProgress) == "string" then
                    previousProgress = 100 -- Si ya se reprodujo, asumir 100%
                end
                
                -- Actualizar el progreso solo si no es "played"
                if questProgressCache[questID] ~= "played" then
                questProgressCache[questID] = questProgress
                end

                debugmodemissionprogress(string.format("Quest: %s (ID: %d) - Progress: %.2f%%", title, questID,
                    questProgress))

                if previousProgress < 50 and questProgress >= 50 then
                    PlayQuestProgressSound(questID, title)
                    ShowNPCFrame(questID, title)
                elseif previousProgress < 100 and questProgress >= 100 then
                    PlayQuestProgressSound(questID, title)
                end
            end
        end
    end
end

local frame = CreateFrame("Frame")
frame:RegisterEvent("QUEST_LOG_UPDATE")
frame:RegisterEvent("CHAT_MSG_MONSTER_SAY")
frame:RegisterEvent("CHAT_MSG_MONSTER_YELL")
frame:RegisterEvent("CHAT_MSG_MONSTER_WHISPER")
frame:RegisterEvent("CHAT_MSG_MONSTER_EMOTE")
frame:SetScript("OnEvent", function(self, event, ...)
    if event == "QUEST_LOG_UPDATE" then
        OnQuestLogUpdate()
    elseif event == "CHAT_MSG_MONSTER_SAY" or event == "CHAT_MSG_MONSTER_YELL"
        or event == "CHAT_MSG_MONSTER_WHISPER" or event == "CHAT_MSG_MONSTER_EMOTE" then
        lastMonsterChatTime = GetTime()
        debugmodemissionprogress(GREEN .. "NPC is speaking, blocking quest progress sounds" .. RESET)
    end
end)

-- Nueva función para desactivar el módulo
local function DeactivateModule()
    isActive = false
    debugmodemissionprogress("|cffff0000QuestProgress module has been deactivated.|r")
    -- Desregistrar el evento para evitar actualizaciones innecesarias
    if frame then
        frame:UnregisterEvent("QUEST_LOG_UPDATE")
    else
        debugmodemissionprogress("|cffffff00Warning: frame is nil in DeactivateModule|r")
    end
end

-- Nueva función para reactivar el módulo si es necesario
local function ActivateModule()
    isActive = true
    debugmodemissionprogress("|cff00ff00QuestProgress module has been activated.|r")
    -- Volver a registrar el evento
    if frame then
        frame:RegisterEvent("QUEST_LOG_UPDATE")
    else
        debugmodemissionprogress("|cffffff00Warning: frame is nil in ActivateModule|r")
    end
end

-- Exponer las funciones de activación/desactivación
VoiceOver.MissionProgress = VoiceOver.MissionProgress or {}
VoiceOver.MissionProgress.Deactivate = DeactivateModule
VoiceOver.MissionProgress.Activate = ActivateModule

-- Función para activar el modo de depuración
local function ActivateDebugMode()
    VoiceOver.MissionProgress.DebugMode = true
    debugmodemissionprogress("|cFF00FF00Quest Progress Debug Mode Activated|r")
end

-- Función para desactivar el modo de depuración
local function DeactivateDebugMode()
    VoiceOver.MissionProgress.DebugMode = false
    debugmodemissionprogress("|cFFFF0000Quest Progress Debug Mode Deactivated|r")
end

-- Exponer las funciones de depuración para que puedan ser llamadas externamente
VoiceOver.MissionProgress = VoiceOver.MissionProgress or {}
VoiceOver.MissionProgress.ActivateDebug = ActivateDebugMode
VoiceOver.MissionProgress.DeactivateDebug = DeactivateDebugMode
