local _, ns = ...

------------------------------------------------------------
-- Release Spirit Blocker
-- Hides the Release Spirit button in guild raids to prevent
-- unnecessary corpse runs. Hold CTRL for 1s to override.
-- Only active in current expansion raids with guild majority.
------------------------------------------------------------

local CTRL_HOLD_DURATION = 1.0  -- seconds to hold CTRL before enabling release

-- State
local isGuildRaid = false
local playerGuild = nil
local blocking = false
local ctrlHeldTime = 0
local overridden = false
local blockerFrame = CreateFrame("Frame", "YYHReleaseBlocker")
local overlayFrame = nil  -- covers the release button with a message

------------------------------------------------------------
-- Condition checks
------------------------------------------------------------
local function UpdateGuildMajority()
    isGuildRaid = false
    if not IsInRaid() then return end

    playerGuild = GetGuildInfo("player")
    if not playerGuild then return end

    local guildCount = 0
    local total = GetNumGroupMembers()
    for i = 1, total do
        local guild = GetGuildInfo("raid" .. i)
        if guild == playerGuild then
            guildCount = guildCount + 1
        end
    end

    isGuildRaid = total > 0 and (guildCount / total) > 0.5
end

local function ShouldBlock()
    local db = YippYappHelperDB or {}
    if db.releaseBlocker == false then return false end
    if not IsInRaid() then return false end
    if not isGuildRaid then return false end
    return true
end

------------------------------------------------------------
-- Find the StaticPopup showing the DEATH dialog
------------------------------------------------------------
local function FindDeathPopup()
    for i = 1, STATICPOPUP_NUMDIALOGS or 4 do
        local popup = _G["StaticPopup" .. i]
        if popup and popup:IsShown() and popup.which == "DEATH" then
            return popup, _G["StaticPopup" .. i .. "Button1"]
        end
    end
    return nil, nil
end

------------------------------------------------------------
-- Overlay: covers the release button with instructions
------------------------------------------------------------
local function CreateOverlay(releaseBtn)
    -- Parent to UIParent (never to the secure StaticPopup button) so this
    -- insecure, mouse-enabled frame can't taint the release button's
    -- protected OnClick path. Positioning is via SetPoint to the button.
    if overlayFrame then
        overlayFrame:ClearAllPoints()
        overlayFrame:SetAllPoints(releaseBtn)
        overlayFrame:SetFrameStrata("DIALOG")
        overlayFrame:SetFrameLevel((releaseBtn:GetFrameLevel() or 0) + 10)
        overlayFrame:Show()
        return overlayFrame
    end

    overlayFrame = CreateFrame("Frame", nil, UIParent)
    overlayFrame:SetAllPoints(releaseBtn)
    overlayFrame:SetFrameStrata("DIALOG")
    overlayFrame:SetFrameLevel((releaseBtn:GetFrameLevel() or 0) + 10)
    overlayFrame:EnableMouse(true)  -- eat clicks

    local bg = overlayFrame:CreateTexture(nil, "BACKGROUND")
    bg:SetAllPoints()
    bg:SetColorTexture(0.1, 0.1, 0.1, 0.9)

    local fs = overlayFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    fs:SetPoint("CENTER")
    fs:SetText("|cffff6060Hold CTRL 1s|r")
    overlayFrame._fs = fs

    -- Progress bar
    local bar = overlayFrame:CreateTexture(nil, "ARTWORK")
    bar:SetHeight(2)
    bar:SetPoint("BOTTOMLEFT", overlayFrame, "BOTTOMLEFT", 2, 2)
    bar:SetColorTexture(0.0, 0.8, 0.0, 1)
    bar:SetWidth(1)
    overlayFrame._bar = bar

    return overlayFrame
end

local warningFrame = nil

local function CreateWarning(popup)
    if warningFrame then
        warningFrame:SetPoint("TOP", popup, "BOTTOM", 0, -20)
        warningFrame:Show()
        return warningFrame
    end

    warningFrame = CreateFrame("Frame", nil, UIParent)
    warningFrame:SetSize(500, 50)
    warningFrame:SetPoint("TOP", popup, "BOTTOM", 0, -16)
    warningFrame:SetFrameStrata("DIALOG")
    warningFrame:SetFrameLevel(100)

    local fs = warningFrame:CreateFontString(nil, "OVERLAY")
    fs:SetFont(STANDARD_TEXT_FONT, 22, "OUTLINE")
    fs:SetPoint("CENTER", 0, 6)
    fs:SetText("|cffff2020YippYapp says DON'T RELEASE!|r")
    warningFrame._fs = fs

    local sub = warningFrame:CreateFontString(nil, "OVERLAY")
    sub:SetFont(STANDARD_TEXT_FONT, 12, "OUTLINE")
    sub:SetPoint("TOP", fs, "BOTTOM", 0, -2)
    sub:SetText("|cffaaaaaa(Hold CTRL for 1s to override)|r")
    warningFrame._sub = sub

    return warningFrame
end

local function HideOverlay()
    if overlayFrame then overlayFrame:Hide() end
    if warningFrame then warningFrame:Hide() end
end

------------------------------------------------------------
-- Block / unblock logic
------------------------------------------------------------
local function ApplyBlock()
    if blocking then return end

    local popup, releaseBtn = FindDeathPopup()
    if not releaseBtn then return end

    blocking = true
    overridden = false
    ctrlHeldTime = 0

    CreateOverlay(releaseBtn)
    CreateWarning(popup)
    local tickAccum = 0
    local TICK = 0.05  -- 20Hz is plenty for a 1s CTRL-hold gate
    blockerFrame:SetScript("OnUpdate", function(self, elapsed)
        tickAccum = tickAccum + elapsed
        if tickAccum < TICK then return end
        local dt = tickAccum
        tickAccum = 0

        -- Check if player is alive or popup dismissed
        if not UnitIsDead("player") or not FindDeathPopup() then
            self:SetScript("OnUpdate", nil)
            HideOverlay()
            blocking = false
            return
        end

        if overridden then return end

        if IsControlKeyDown() then
            ctrlHeldTime = ctrlHeldTime + dt
            -- Update progress bar
            if overlayFrame and overlayFrame._bar then
                local pct = math.min(ctrlHeldTime / CTRL_HOLD_DURATION, 1)
                local maxW = overlayFrame:GetWidth() - 4
                overlayFrame._bar:SetWidth(math.max(maxW * pct, 1))
            end
            if ctrlHeldTime >= CTRL_HOLD_DURATION then
                overridden = true
                HideOverlay()
                print("|cff00ff00YippYapp|r: Release enabled")
            end
        else
            if ctrlHeldTime > 0 then
                ctrlHeldTime = 0
                -- Reset progress bar
                if overlayFrame and overlayFrame._bar then
                    overlayFrame._bar:SetWidth(1)
                end
            end
        end
    end)
end

local function ClearBlock()
    blocking = false
    overridden = false
    ctrlHeldTime = 0
    blockerFrame:SetScript("OnUpdate", nil)
    HideOverlay()
end

------------------------------------------------------------
-- Event handling
------------------------------------------------------------
blockerFrame:RegisterEvent("PLAYER_ENTERING_WORLD")
blockerFrame:RegisterEvent("ZONE_CHANGED_NEW_AREA")
blockerFrame:RegisterEvent("GROUP_ROSTER_UPDATE")
blockerFrame:RegisterEvent("PLAYER_DEAD")
blockerFrame:RegisterEvent("PLAYER_ALIVE")
blockerFrame:RegisterEvent("PLAYER_UNGHOST")

blockerFrame:SetScript("OnEvent", function(self, event)
    if event == "PLAYER_ENTERING_WORLD" or event == "ZONE_CHANGED_NEW_AREA" then
        UpdateGuildMajority()
        -- Clear block if we left the raid
        if blocking and not ShouldBlock() then
            ClearBlock()
        end

    elseif event == "GROUP_ROSTER_UPDATE" then
        UpdateGuildMajority()

    elseif event == "PLAYER_DEAD" then
        if ShouldBlock() then
            -- Slight delay to let the StaticPopup appear
            C_Timer.After(0.1, function()
                if UnitIsDead("player") and ShouldBlock() then
                    ApplyBlock()
                end
            end)
        end

    elseif event == "PLAYER_ALIVE" or event == "PLAYER_UNGHOST" then
        ClearBlock()
    end
end)

------------------------------------------------------------
-- Public toggle
------------------------------------------------------------
function ns:IsReleaseBlockerEnabled()
    local db = YippYappHelperDB or {}
    return db.releaseBlocker ~= false
end

function ns:ToggleReleaseBlocker()
    YippYappHelperDB = YippYappHelperDB or {}
    local newState = not self:IsReleaseBlockerEnabled()
    YippYappHelperDB.releaseBlocker = newState
    if not newState and blocking then
        ClearBlock()
    end
    return newState
end

------------------------------------------------------------
-- Leader broadcast: suggest release blocker state to raid
------------------------------------------------------------
local RB_COMM_PREFIX = "YYH_RB"
C_ChatInfo.RegisterAddonMessagePrefix(RB_COMM_PREFIX)

function ns:BroadcastReleaseBlockerState(enabled)
    if not IsInRaid() then return end
    -- Only broadcast if leader or assist
    local myIndex = UnitInRaid("player")
    if not myIndex then return end
    local _, rank = GetRaidRosterInfo(myIndex + 1)
    if not rank or rank < 1 then return end

    local msg = enabled and "RB:ON" or "RB:OFF"
    C_ChatInfo.SendAddonMessage(RB_COMM_PREFIX, msg, "RAID")
end

local rbCommFrame = CreateFrame("Frame")
rbCommFrame:RegisterEvent("CHAT_MSG_ADDON")
rbCommFrame:SetScript("OnEvent", function(self, event, prefix, msg, _, sender)
    if event ~= "CHAT_MSG_ADDON" or prefix ~= RB_COMM_PREFIX then return end
    if not IsInRaid() then return end

    -- Only accept from leader/assist
    local shortSender = Ambiguate(sender, "short")
    local senderRank = nil
    for i = 1, GetNumGroupMembers() do
        local name, rank = GetRaidRosterInfo(i)
        if name and Ambiguate(name, "short") == shortSender then
            senderRank = rank
            break
        end
    end
    if not senderRank or senderRank < 1 then return end

    -- Don't override if it's from ourselves
    if UnitIsUnit(sender, "player") then return end

    local cmd = strsplit(":", msg)
    if cmd == "RB" then
        local _, state = strsplit(":", msg)
        if state == "ON" then
            YippYappHelperDB = YippYappHelperDB or {}
            YippYappHelperDB.releaseBlocker = true
            print("|cff00ff00YippYapp|r: Raid leader enabled Release Blocker for the raid")
        elseif state == "OFF" then
            YippYappHelperDB = YippYappHelperDB or {}
            YippYappHelperDB.releaseBlocker = false
            if blocking then ClearBlock() end
            print("|cff00ff00YippYapp|r: Raid leader disabled Release Blocker for the raid")
        end
        -- Keep the in-raid-frame button and the Settings-panel checkbox
        -- in sync after a leader broadcast flips our flag.
        if ns.RefreshReleaseBlockerButton then ns.RefreshReleaseBlockerButton() end
        if ns.NotifySettingChanged then ns.NotifySettingChanged("YYH_RELEASE_BLOCKER") end
    end
end)

