setfenv(1, VoiceOver)

local questProgressCache = {}
local isActive = true
local isNpcSpeaking = false

-- 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
        print("|cFF00FF00[MissionProgress Debug]|r " .. message)
    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)
    if not isActive or isNpcSpeaking then return end    -- No hacer nada si el módulo está desactivado o si un NPC está hablando

    local npcID, npcName = GetNPCInfoByQuestID(questID) -- Obtener el segundo valor
    npcName = npcName or "Unknown"

    local duration = GetSoundDuration(questID)

    local soundData = {
        event = Enums.SoundEvent.QuestProgress,
        questID = questID,
        name = npcName,
        title = questTitle,
        unitGUID = npcID and string.format("Creature-0-0-0-0-%d", npcID) or nil,
        unitIsObjectOrItem = Utils:IsNPCObjectOrItem(),
        addedCallback = QuestSoundDataAdded,
        length = duration
    }

    local showDuration = 2
    C_Timer.After(showDuration, function()
        SoundQueue:AddSoundToQueue(soundData)
    end)
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)
    if not isActive or isNpcSpeaking then return end -- No reproducir sonido si el módulo está desactivado o si un NPC está hablando

    if not questProgressCache[questID] then
        local soundPath = string.format(
        "Interface\\AddOns\\AI_VoiceOverData_WarWithin\\generated\\sounds\\quests\\%d-progress.mp3", questID)
        PlaySoundFile(soundPath)
        questProgressCache[questID] = true -- Marcar la misión como reproducida
    end
end

local function OnQuestLogUpdate()
    if not isActive or isNpcSpeaking then return end -- No hacer nada si el módulo está desactivado o si un NPC está hablando

    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
                questProgressCache[questID] = questProgress

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

                if previousProgress < 50 and questProgress >= 50 then
                    PlayQuestProgressSound(questID)
                    ShowNPCFrame(questID, title)
                elseif previousProgress < 100 and questProgress >= 100 then
                    PlayQuestProgressSound(questID)
                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
        isNpcSpeaking = true
        debugmodemissionprogress(GREEN .. "NPC is speaking, blocking quest progress sounds" .. RESET)

        -- Después de 5 segundos (o la duración que necesites), asumimos que el NPC ha terminado de hablar
        C_Timer.After(5, function()
            isNpcSpeaking = false
            debugmodemissionprogress(GREEN .. "NPC has likely finished speaking, resuming quest progress sounds" .. RESET)
        end)
    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
