-- Pedro Addon 12.0.1 Rewrite
-- Author: Darthcutie

-- Define PedroSounds
local PedroSounds = {
    {name = "Pedro", path = "Interface\\AddOns\\Pedro\\Media\\Pedro.ogg", duration = 9},
    {name = "PedroLong", path = "Interface\\AddOns\\Pedro\\Media\\PedroLong.ogg", duration = 40},
    {name = "GoldenKpop", path = "Interface\\AddOns\\Pedro\\Media\\GoldenKpop.ogg", duration = 48},
}

-- Audio channels
local PedroAudioChannels = {
    {name = "Master (Default, Recommended)", value = "Master"},
    {name = "Sound Effects (Recommended if sound cuts out)", value = "SFX"},
    {name = "Dialog (Not recommended)", value = "Dialog"},
    {name = "Music (Not recommended)", value = "Music"},
    {name = "Ambience (Not recommended)", value = "Ambience"},
}

-- Initialize PedroDB safely
PedroDB = PedroDB or {}
PedroDB.hasteThreshold = PedroDB.hasteThreshold or 30
PedroDB.selectedSound = PedroDB.selectedSound or PedroSounds[1].path
PedroDB.audioChannel = PedroDB.audioChannel or "Master"

-- Core state variables
local lustActive = false
local canPlay = true
local lastTriggerTime = nil
local baseHaste = nil
local baseHasteAnnounced = false
local tickerInCombat = nil

local cooldown = 1.5
local baseDelay = 5
local lustGuardDuration = 45 -- seconds between allowed Pedro triggers

local pedroSound = PedroDB.selectedSound
local pedroAudioChannel = PedroDB.audioChannel
local pedroPlayingID = nil

-- Buff names for out-of-combat detection
local lustBuffs = {
    "Bloodlust", "Heroism", "Time Warp", "Ancient Hysteria",
    "Harrier's Cry", "Primal Rage", "Fury of the Aspects"
}

-- Rolling average logic for haste
local historySize = 5
local tickInterval = 1
local historyWeights = {1, 1, 1, 2, 3}
local hasteHistory = {}

-- Add new haste value to history
local function AddHasteTick(value)
    table.insert(hasteHistory, value)
    if #hasteHistory > historySize then
        table.remove(hasteHistory, 1)
    end
end

-- NEW: Get dynamic weights based on user-selected threshold
local function GetDynamicWeights()
    local threshold = PedroDB.hasteThreshold or 30

    if threshold == 30 then
        return {1, 1, 1, 2, 3}
    elseif threshold >= 35 and threshold < 45 then
        return {1, 1, 1, 3, 4}
    elseif threshold >= 45 then
        return {1, 1, 2, 3, 4}
    end

    return {1, 1, 1, 2, 3}
end

-- Compute weighted average of haste values using dynamic weights
local function ComputeWeightedAverage()
    local weights = GetDynamicWeights()
    local sum, total = 0, 0
    for i = 1, #hasteHistory do
        local weight = weights[i] or 1
        sum = sum + hasteHistory[i] * weight
        total = total + weight
    end
    return total > 0 and sum / total or 0
end

-- Reset short cooldown
local function ResetCooldown()
    canPlay = true
end

-- Centralized Pedro sound playback
-- 'ignoreGuard' lets manual plays bypass the 45s lustGuardDuration
local function PlayPedroIfAllowed(ignoreGuard)
    -- Automatic play respects canPlay and lustGuardDuration
    if not ignoreGuard then
        if not canPlay then return end
        if lastTriggerTime and (GetTime() - lastTriggerTime) < lustGuardDuration then return end
    end

    -- Stop previous sound if it's a valid handle
    if type(pedroPlayingID) == "number" then
        StopSound(pedroPlayingID)
        pedroPlayingID = nil
    end

    -- Play the selected sound on the selected channel
    pedroPlayingID = PlaySoundFile(pedroSound, pedroAudioChannel)

    -- Only update guard/cooldown if this is automatic
    if not ignoreGuard then
        canPlay = false
        lastTriggerTime = GetTime()
        C_Timer.After(cooldown, ResetCooldown)
    end
end

-- In-combat haste detection
local function CheckLustByHaste()
    if not baseHaste or baseHaste <= 0 then return end

    local currentHaste = UnitSpellHaste("player") or 0
    AddHasteTick(currentHaste)

    local weightedHaste = ComputeWeightedAverage()
    local threshold = PedroDB.hasteThreshold or 30
    local totalThreshold = baseHaste + threshold

    if weightedHaste >= totalThreshold then
        lustActive = true
        PlayPedroIfAllowed()
    else
        lustActive = false
    end
end

local function CheckLustByBuff()
    -- skip in Edit Mode to avoid unnecessary calls
    if EditModeManager and EditModeManager:ShouldIgnoreUnitEvents() then
        return false
    end

    if not AuraUtil or not AuraUtil.FindAuraByName then
        return false
    end

    for _, buffName in ipairs(lustBuffs) do
        -- protected call prevents crash if internal API is not loaded
        local ok, name = pcall(AuraUtil.FindAuraByName, buffName, "player", "HELPFUL")
        if ok and name then
            return true
        end
    end
    return false
end


-- Central trigger for both in/out-of-combat
local function TryPlayPedro()
    if InCombatLockdown() then
        CheckLustByHaste()
    else
        local hasLust = CheckLustByBuff()
        lustActive = hasLust
        if hasLust then
            PlayPedroIfAllowed()
        end
    end
end

-- Manual play
local function TryPlayPedroManual()
    -- Pass 'true' to ignore the guard so manual plays always work
    PlayPedroIfAllowed(true)
    print("Pedro sound played manually!")
end

-- Show Sound Selection Frame
local function ShowSoundFrame()
    local SoundFrame = CreateFrame("Frame", "PedroSoundSelector", UIParent, "BasicFrameTemplateWithInset")
    local count = #PedroSounds
    SoundFrame:SetSize(200, 120 + (count * 25) + 35)
    SoundFrame:SetPoint("CENTER")
    SoundFrame:SetMovable(true)
    SoundFrame:EnableMouse(true)
    SoundFrame:RegisterForDrag("LeftButton")
    SoundFrame:SetScript("OnDragStart", SoundFrame.StartMoving)
    SoundFrame:SetScript("OnDragStop", SoundFrame.StopMovingOrSizing)

    SoundFrame.title = SoundFrame:CreateFontString(nil, "OVERLAY")
    SoundFrame.title:SetFontObject("GameFontHighlight")
    SoundFrame.title:SetPoint("TOP", 0, -5)
    SoundFrame.title:SetText("Select Pedro Sound")

    local okButton = CreateFrame("Button", nil, SoundFrame, "UIPanelButtonTemplate")
    okButton:SetSize(80, 22)
    okButton:SetPoint("BOTTOM", 0, 10)
    okButton:SetText("OK")
    okButton:SetScript("OnClick", function()
        SoundFrame:Hide()
    end)

    local radioButtons = {}
    for i, sound in ipairs(PedroSounds) do
        local btn = CreateFrame("CheckButton", "PedroSoundBtn"..i, SoundFrame, "UICheckButtonTemplate")
        btn:SetPoint("TOPLEFT", 10, -(i * 25) - 20)
        btn.text:SetText(string.format("%s - %d second%s", sound.name, sound.duration or 0, (sound.duration == 1 and "" or "s")))

        if PedroDB.selectedSound == sound.path then
            btn:SetChecked(true)
        end

        btn:SetScript("OnClick", function(self)
            for _, other in ipairs(radioButtons) do
                if other ~= self then other:SetChecked(false) end
            end
            PedroDB.selectedSound = sound.path
            pedroSound = sound.path
            print("Pedro: Selected song " .. sound.name)
        end)
        table.insert(radioButtons, btn)
    end
    SoundFrame:Show()
end							   

-- Show Audio Channel Selection Frame
local function ShowAudioChannelFrame()
    local ChannelFrame = CreateFrame("Frame", "PedroAudioSelector", UIParent, "BasicFrameTemplateWithInset")
    local count = #PedroAudioChannels
    ChannelFrame:SetSize(320, 120 + (count * 25) + 35)
    ChannelFrame:SetPoint("CENTER")
    ChannelFrame:SetMovable(true)
    ChannelFrame:EnableMouse(true)
    ChannelFrame:RegisterForDrag("LeftButton")
    ChannelFrame:SetScript("OnDragStart", ChannelFrame.StartMoving)
    ChannelFrame:SetScript("OnDragStop", ChannelFrame.StopMovingOrSizing)

    ChannelFrame.title = ChannelFrame:CreateFontString(nil, "OVERLAY")
    ChannelFrame.title:SetFontObject("GameFontHighlight")
    ChannelFrame.title:SetPoint("TOP", 0, -5)
    ChannelFrame.title:SetText("Select Audio Channel")

    local okButton = CreateFrame("Button", nil, ChannelFrame, "UIPanelButtonTemplate")
    okButton:SetSize(80, 22)
    okButton:SetPoint("BOTTOM", 0, 10)
    okButton:SetText("OK")
    okButton:SetScript("OnClick", function()
        ChannelFrame:Hide()
    end)

    local radioButtons = {}
    for i, channel in ipairs(PedroAudioChannels) do
        local btn = CreateFrame("CheckButton", "PedroAudioBtn"..i, ChannelFrame, "UICheckButtonTemplate")
        btn:SetPoint("TOPLEFT", 10, -(i * 25) - 20)
        btn.text:SetText(channel.name)

        if PedroDB.audioChannel == channel.value then
            btn:SetChecked(true)
        end

        btn:SetScript("OnClick", function(self)
            for _, other in ipairs(radioButtons) do
                if other ~= self then other:SetChecked(false) end
            end
            PedroDB.audioChannel = channel.value
            pedroAudioChannel = channel.value
            print("Pedro: Audio channel set to " .. channel.name)
        end)
        table.insert(radioButtons, btn)
    end
    ChannelFrame:Show()
end

-- StaticPopup for setting haste threshold
StaticPopupDialogs["PEDRO_SET_THRESHOLD"] = {
    text = "Enter a new haste threshold (30-99):",
    button1 = "OK",
    button2 = "Cancel",
    hasEditBox = true,
    maxLetters = 2,
    editBoxWidth = 80,

    OnShow = function(self)
        local editBox = self.editBox or _G[self:GetName() .. "EditBox"]
        if editBox then
            local threshold = PedroDB.hasteThreshold or 30
            editBox:SetText(threshold)
            editBox:SetFocus()
        end
    end,

    OnAccept = function(self)
        local editBox = self.editBox or _G[self:GetName() .. "EditBox"]
        if editBox then
            local threshold = tonumber(editBox:GetText())
            if threshold and threshold >= 30 and threshold <= 99 then
                PedroDB.hasteThreshold = threshold
                print("Pedro: Haste threshold set to " .. threshold .. "%")
            else
                print("Pedro: Invalid threshold. Must be between 30 and 99.")
            end
			
																				   
        end
    end,

    timeout = 0,
    whileDead = true,
    hideOnEscape = true,
}

-- /pedro debug command
SLASH_PEDRO1 = "/pedro"
SlashCmdList.PEDRO = function()
    local currentHaste = UnitSpellHaste("player") or 0
    local triggerInfo = lastTriggerTime and date("%H:%M:%S", lastTriggerTime) or "never"
    local soundName = PedroDB.selectedSound or "Pedro.ogg"
    local audioChannel = PedroDB.audioChannel or "Master"
    local hasteThreshold = PedroDB.hasteThreshold or 30

    print(string.format(
        "Pedro Debug: Base: %.2f%% | Current: %.2f%% | Last Trigger: %s | Haste Threshold: %d%% | Sound: %s | Channel: %s",
        baseHaste or 0,
        currentHaste,
        triggerInfo,
        hasteThreshold,
        soundName,
        audioChannel
    ))
end


-- Main frame
local f = CreateFrame("Frame")
f:RegisterEvent("ADDON_LOADED")
f:RegisterEvent("PLAYER_ENTERING_WORLD")
f:RegisterEvent("UNIT_AURA")
f:RegisterEvent("UNIT_STATS")
f:RegisterEvent("PLAYER_EQUIPMENT_CHANGED")
f:RegisterEvent("TRAIT_CONFIG_UPDATED")
f:RegisterEvent("PLAYER_REGEN_DISABLED")
f:RegisterEvent("PLAYER_REGEN_ENABLED")

f:SetScript("OnEvent", function(self, event, arg1)
    if event == "ADDON_LOADED" and arg1 == "Pedro" then
        PedroDB = PedroDB or {}
        PedroDB.selectedSound = PedroDB.selectedSound or PedroSounds[1].path
        PedroDB.audioChannel = PedroDB.audioChannel or "Master"
        PedroDB.useAltSound = PedroDB.useAltSound or false
        PedroDB.useGoldenKpop = PedroDB.useGoldenKpop or false
        PedroDB.minimapPos = PedroDB.minimapPos or 220
        pedroSound = PedroDB.selectedSound
        pedroAudioChannel = PedroDB.audioChannel
        print("Pedro: Loaded, using sound " .. (PedroDB.useGoldenKpop and "GoldenKpop.ogg" or (PedroDB.useAltSound and "PedroLong.ogg" or "Pedro.ogg")))

        -- Minimap icon setup
        local LDB = LibStub("LibDataBroker-1.1")
        local LDBI = LibStub("LibDBIcon-1.0")
        local PedroLDB = LDB:NewDataObject("Pedro", {
            type = "launcher",
            icon = "Interface\\AddOns\\Pedro\\Media\\Pedro.tga",
            label = "Pedro",
            OnClick = function(_, button)
                if button == "LeftButton" then
                    SlashCmdList.PEDRO()
                elseif button == "RightButton" then
                    local dropdown = CreateFrame("Frame", "PedroDropdown", UIParent, "UIDropDownMenuTemplate")
                    UIDropDownMenu_Initialize(dropdown, function(self, level)
                        if level == 1 then
                            UIDropDownMenu_AddButton({text = "Play Pedro Now", func = TryPlayPedroManual})
                            UIDropDownMenu_AddButton({text = "Select Song", func = ShowSoundFrame})
                            UIDropDownMenu_AddButton({text = "Select Audio Channel", func = ShowAudioChannelFrame})
                            UIDropDownMenu_AddButton({text = "Reset Audio Channel", func = function()
                                PedroDB.audioChannel = "Master"
                                pedroAudioChannel = "Master"
                                print("Pedro: Audio channel reset to Master")
                            end})
                            UIDropDownMenu_AddButton({text = "Set Haste Threshold", func = function() StaticPopup_Show("PEDRO_SET_THRESHOLD") end})
                            UIDropDownMenu_AddButton({text = "Reset Haste Threshold", func = function()
                                PedroDB.hasteThreshold = nil
                                print("Pedro: Threshold reset to default (30%)")
                            end})
                            UIDropDownMenu_AddButton({text = "Reset Base Haste", func = function()
                                baseHaste = UnitSpellHaste("player") or 0
                                wipe(hasteHistory)
                                print(string.format("Pedro: Base haste reset to %.2f%%", baseHaste))
                            end})
                        end
                    end)
                    ToggleDropDownMenu(1, nil, dropdown, "cursor", 0, 0)
                end
            end,
            OnTooltipShow = function(tt)
                tt:AddLine("Pedro")
                tt:AddLine("Left-Click: Show debug")
                tt:AddLine("Right-Click: Options")
            end,
        })
        LDBI:Register("Pedro", PedroLDB, PedroDB)
        LDBI:Show("Pedro")

    elseif event == "PLAYER_ENTERING_WORLD" then
        lustActive = false
        canPlay = true
        lastTriggerTime = nil
        baseHaste = nil

        C_Timer.After(baseDelay, function()
            baseHaste = UnitSpellHaste("player") or 0
            if not baseHasteAnnounced then
                print(string.format("Pedro: Base haste initialized: %.2f%%", baseHaste))
                baseHasteAnnounced = true
            end
        end)

    elseif event == "UNIT_AURA" or event == "UNIT_STATS" then
        if arg1 == "player" then
            TryPlayPedro()
        end

    elseif event == "PLAYER_EQUIPMENT_CHANGED" or event == "TRAIT_CONFIG_UPDATED" then
        baseHaste = UnitSpellHaste("player") or 0
        wipe(hasteHistory)

    elseif event == "PLAYER_REGEN_DISABLED" then
        if tickerInCombat then
            tickerInCombat:Cancel()
            tickerInCombat = nil
        end
        tickerInCombat = C_Timer.NewTicker(tickInterval, CheckLustByHaste)

    elseif event == "PLAYER_REGEN_ENABLED" then
        if tickerInCombat then
            tickerInCombat:Cancel()
            tickerInCombat = nil
        end
        TryPlayPedro()
    end
end)
