-- modules/HealerCCAlert.lua
-- Healer In CC Alert - Center-screen notification when your healer is crowd controlled in arena
-- Event-driven using UNIT_AURA (no polling/timers)

local _, addon = ...
local AC = _G.ArenaCore
if not AC then return end

AC.HealerCCAlert = AC.HealerCCAlert or {}
local HCA = AC.HealerCCAlert

-- State tracking
local __alertFrame = nil
local __eventFrame = nil
local __enabled = false
local __currentHealerUnit = nil
local __rosterDebounceTimer = nil
local __testActive = false
local __testTimer = nil

-- Party units to check for healers
local PARTY_UNITS = { "player", "party1", "party2", "party3", "party4" }

-- ============================================================================
-- DATABASE ACCESS
-- ============================================================================

local function GetDB()
    local db = AC.DB and AC.DB.profile and AC.DB.profile.bigDebuffs
    if not db then
        db = {
            healerCCAlert = false,
        }
    end
    return db
end

-- ============================================================================
-- HEALER DETECTION
-- ============================================================================

local function FindHealerInParty()
    for _, unit in ipairs(PARTY_UNITS) do
        if UnitExists(unit) and not UnitIsDeadOrGhost(unit) then
            local role = UnitGroupRolesAssigned(unit)
            if role == "HEALER" then
                return unit
            end
        end
    end
    return nil
end

-- ============================================================================
-- CC DETECTION (uses same API as BigDebuffs)
-- ============================================================================

local function GetHealerCCStatus(unit)
    if not unit or not UnitExists(unit) then return nil end
    if not C_LossOfControl then return nil end
    
    local count = C_LossOfControl.GetActiveLossOfControlDataCountByUnit(unit) or 0
    if count == 0 then return nil end
    
    -- Get highest priority CC (track the index separately)
    local bestPriority = -1
    local bestData = nil
    local bestIndex = nil
    
    for i = 1, count do
        local data = C_LossOfControl.GetActiveLossOfControlDataByUnit(unit, i)
        if data and data.priority and data.priority > bestPriority then
            bestPriority = data.priority
            bestData = data
            bestIndex = i
        end
    end
    
    if not bestData or not bestData.auraInstanceID or not bestIndex then return nil end
    
    -- Get aura data for icon
    local icon = nil
    local auraData = C_UnitAuras and C_UnitAuras.GetAuraDataByAuraInstanceID(unit, bestData.auraInstanceID)
    if auraData and auraData.icon then
        icon = auraData.icon
    elseif bestData.iconTexture then
        icon = bestData.iconTexture
    end
    if not icon then return nil end
    
    -- Get duration object
    local durationObj = C_LossOfControl.GetActiveLossOfControlDuration(unit, bestIndex)
    if not durationObj then return nil end
    
    return {
        icon = icon,
        durationObj = durationObj,
        locIndex = bestIndex,
    }
end

-- ============================================================================
-- ALERT FRAME CREATION
-- ============================================================================

local function CreateAlertFrame()
    if __alertFrame then return __alertFrame end

    local frame = CreateFrame("Frame", "ArenaCoreHealerCCAlert", UIParent)
    frame:SetSize(200, 80)
    frame:SetFrameStrata("HIGH")
    frame:SetFrameLevel(999)
    frame:SetClipsChildren(true)
    frame:Hide()

    -- Load saved position from database
    local db = GetDB()
    local pos = db.healerCCAlertPosition or {
      point       = "CENTER",
      relativeTo  = "UIParent",
      relativePoint = "CENTER",
      xOfs        = 0,
      yOfs        = 0,
    }
    frame:SetPoint(pos.point, pos.relativeTo, pos.relativePoint, pos.xOfs, pos.yOfs)
    
    -- Dark background with subtle red tint (like Gear Reminder)
    local bg = frame:CreateTexture(nil, "BACKGROUND")
    bg:SetAllPoints()
    bg:SetColorTexture(0.03, 0.01, 0.01, 0.96)
    frame.bg = bg

    -- Scan lines - horizontal subtle stripes for that CRT / alert vibe
    local scanGroup = CreateFrame("Frame", nil, frame)
    scanGroup:SetAllPoints()
    for i = 1, 20 do
        local line = scanGroup:CreateTexture(nil, "BORDER", nil, -1)
        line:SetHeight(1)
        line:SetColorTexture(0, 0, 0, 0.25)
        line:SetPoint("TOPLEFT", scanGroup, "TOPLEFT", 2, -(i * 6))
        line:SetPoint("TOPRIGHT", scanGroup, "TOPRIGHT", -2, -(i * 6))
    end
    frame.scanGroup = scanGroup

    -- Outer red border (2px)
    local borderOuter = frame:CreateTexture(nil, "BORDER")
    borderOuter:SetPoint("TOPLEFT", frame, "TOPLEFT", 0, 0)
    borderOuter:SetPoint("TOPRIGHT", frame, "TOPRIGHT", 0, 0)
    borderOuter:SetHeight(2)
    borderOuter:SetColorTexture(0.75, 0.05, 0.05, 1)

    local borderBot = frame:CreateTexture(nil, "BORDER")
    borderBot:SetPoint("BOTTOMLEFT", frame, "BOTTOMLEFT", 0, 0)
    borderBot:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", 0, 0)
    borderBot:SetHeight(2)
    borderBot:SetColorTexture(0.75, 0.05, 0.05, 1)

    local borderLeft = frame:CreateTexture(nil, "BORDER")
    borderLeft:SetPoint("TOPLEFT", frame, "TOPLEFT", 0, -2)
    borderLeft:SetPoint("BOTTOMLEFT", frame, "BOTTOMLEFT", 0, 2)
    borderLeft:SetWidth(2)
    borderLeft:SetColorTexture(0.75, 0.05, 0.05, 1)

    local borderRight = frame:CreateTexture(nil, "BORDER")
    borderRight:SetPoint("TOPRIGHT", frame, "TOPRIGHT", 0, -2)
    borderRight:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", 0, 2)
    borderRight:SetWidth(2)
    borderRight:SetColorTexture(0.75, 0.05, 0.05, 1)

    -- Inner glow / accent
    local innerGlow = frame:CreateTexture(nil, "BACKGROUND", nil, 1)
    innerGlow:SetPoint("TOPLEFT", frame, "TOPLEFT", 4, -4)
    innerGlow:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -4, 4)
    innerGlow:SetColorTexture(0.25, 0.02, 0.02, 0.15)
    frame.innerGlow = innerGlow
    
    -- Alert text
    local text = frame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    text:SetFont(AC.FONT_PATH or "Interface\\AddOns\\ArenaCore\\Media\\Fonts\\arenacore.ttf", 16, "OUTLINE")
    text:SetText("Healer Is Shafted!")
    text:SetPoint("TOP", 0, -10)
    text:SetTextColor(1, 0.4, 0.4, 1)
    frame.text = text
    
    -- CC icon container (clips cooldown animation to stay within bounds)
    local iconContainer = CreateFrame("Frame", nil, frame)
    iconContainer:SetSize(40, 40)
    iconContainer:SetPoint("CENTER", 0, -10)
    frame.iconContainer = iconContainer

    -- CC icon
    local icon = iconContainer:CreateTexture(nil, "ARTWORK")
    icon:SetSize(40, 40)
    icon:SetPoint("CENTER")
    icon:SetTexCoord(0.08, 0.92, 0.08, 0.92)
    icon:Hide()
    frame.icon = icon

    -- Cooldown for timer (parented to iconContainer to clip animation)
    local cd = CreateFrame("Cooldown", nil, iconContainer, "CooldownFrameTemplate")
    cd:SetSize(40, 40)
    cd:SetPoint("CENTER")
    cd:SetReverse(true)
    cd:SetDrawEdge(true)
    if cd.SetHideCountdownNumbers then
        cd:SetHideCountdownNumbers(false)
    end
    frame.cooldown = cd
    
    -- Make frame draggable
    frame:SetMovable(true)
    frame:EnableMouse(true)
    frame:RegisterForDrag("LeftButton")
    frame:SetScript("OnDragStart", function() frame:StartMoving() end)
    frame:SetScript("OnDragStop", function()
      frame:StopMovingOrSizing()
      -- Save position to database
      local db = GetDB()
      local point, relativeTo, relativePoint, xOfs, yOfs = frame:GetPoint()
      db.healerCCAlertPosition = {
        point       = point,
        relativeTo  = relativeTo and relativeTo:GetName() or "UIParent",
        relativePoint = relativePoint,
        xOfs        = xOfs,
        yOfs        = yOfs,
      }
    end)
    
    __alertFrame = frame
    return frame
end

-- ============================================================================
-- ALERT DISPLAY LOGIC
-- ============================================================================

local function ShowAlert(ccData)
    local frame = CreateAlertFrame()
    if not frame then return end
    
    -- Set icon
    if ccData.icon then
        frame.icon:SetTexture(ccData.icon)
        frame.icon:Show()
    end
    
    -- Set cooldown
    if ccData.durationObj and frame.cooldown.SetCooldownFromDurationObject then
        local ok = pcall(frame.cooldown.SetCooldownFromDurationObject, frame.cooldown, ccData.durationObj, true)
        if not ok then
            frame.cooldown:Clear()
        end
    end
    
    frame:Show()
end

local function HideAlert()
    if __alertFrame then
        __alertFrame:Hide()
    end
end

-- ============================================================================
-- EVENT-DRIVEN HEALER TRACKING
-- ============================================================================

-- Midnight fires UNIT_AURA constantly, so we bail early when the payload
-- doesn't actually carry any changes worth reacting to.
local function AuraPayloadHasChanges(updateInfo)
    if not updateInfo or updateInfo.isFullUpdate then return true end
    local added   = updateInfo.addedAuras
    local updated = updateInfo.updatedAuraInstanceIDs
    local removed = updateInfo.removedAuraInstanceIDs
    if added   and #added   > 0 then return true end
    if updated and #updated > 0 then return true end
    if removed and #removed > 0 then return true end
    return false
end

local function RegisterHealerAuraWatcher(unit)
    if not __eventFrame then return end
    __eventFrame:RegisterUnitEvent("UNIT_AURA", unit)
end

local function UnregisterHealerAuraWatcher(unit)
    if not __eventFrame then return end
    __eventFrame:UnregisterEvent("UNIT_AURA")
end

local function UpdateHealerAuraWatcher()
    -- Unregister old healer
    if __currentHealerUnit then
        UnregisterHealerAuraWatcher(__currentHealerUnit)
    end
    
    -- Find new healer
    local newHealer = FindHealerInParty()
    __currentHealerUnit = newHealer
    
    -- Register new healer if found
    if newHealer then
        RegisterHealerAuraWatcher(newHealer)
        -- Check current CC status immediately
        local ccData = GetHealerCCStatus(newHealer)
        if ccData then
            ShowAlert(ccData)
        else
            HideAlert()
        end
    else
        HideAlert()
    end
end

-- ============================================================================
-- UNIT_AURA EVENT HANDLER
-- ============================================================================

local function OnUnitAura(unit, updateInfo)
    if not __enabled then return end
    
    -- Skip if not our healer
    if unit ~= __currentHealerUnit then return end
    
    -- Skip irrelevant aura changes (Midnight optimization)
    if not AuraPayloadHasChanges(updateInfo) then return end
    
    -- Check CC status
    local ccData = GetHealerCCStatus(unit)
    if ccData then
        ShowAlert(ccData)
    else
        HideAlert()
    end
end

-- ============================================================================
-- PUBLIC API
-- ============================================================================

function HCA:Toggle(enabled)
    __enabled = (enabled == true)
    
    if __enabled then
        -- Check if in arena
        local _, instanceType = IsInInstance()
        if instanceType == "arena" then
            UpdateHealerAuraWatcher()
        else
            HideAlert()
        end
    else
        -- Unregister all aura watchers
        if __currentHealerUnit then
            UnregisterHealerAuraWatcher(__currentHealerUnit)
            __currentHealerUnit = nil
        end
        HideAlert()
    end
end

function HCA:Initialize()
    if self.__initialized then return end
    self.__initialized = true
    
    -- Create event frame
    __eventFrame = CreateFrame("Frame")
    
    -- Register for group roster updates (debounced)
    __eventFrame:RegisterEvent("GROUP_ROSTER_UPDATE")
    __eventFrame:RegisterEvent("PLAYER_ENTERING_WORLD")
    __eventFrame:RegisterEvent("ZONE_CHANGED_NEW_AREA")
    
    __eventFrame:SetScript("OnEvent", function(_, event, unit, ...)
        if event == "UNIT_AURA" then
            OnUnitAura(unit, ...)
        elseif event == "GROUP_ROSTER_UPDATE" then
            -- Debounce healer rescan to avoid rapid re-registrations
            if __rosterDebounceTimer then
                __rosterDebounceTimer:Cancel()
            end
            __rosterDebounceTimer = C_Timer.After(0.5, function()
                if __enabled then
                    UpdateHealerAuraWatcher()
                end
            end)
        elseif event == "PLAYER_ENTERING_WORLD" or event == "ZONE_CHANGED_NEW_AREA" then
            -- Check if we should be enabled
            local db = GetDB()
            if db.healerCCAlert then
                local _, instanceType = IsInInstance()
                if instanceType == "arena" then
                    self:Toggle(true)
                else
                    self:Toggle(false)
                end
            end
        end
    end)
    
    -- Initial check
    C_Timer.After(1, function()
        local db = GetDB()
        if db.healerCCAlert then
            self:Toggle(true)
        end
    end)
end

-- ============================================================================
-- TEST ALERT (for preview in settings)
-- ============================================================================

local TEST_ICON = 136071 -- Polymorph (sheep)

function HCA:ShowTestAlert()
    -- Force recreation of frame for test mode to ensure fresh cooldown state
    if __alertFrame then
        __alertFrame:Hide()
        __alertFrame = nil
    end

    local frame = CreateAlertFrame()
    if not frame then return end

    -- Fake CC data for preview
    frame.icon:SetTexture(TEST_ICON)
    frame.icon:Show()

    -- Recreate cooldown frame for fresh state
    if frame.cooldown then
        frame.cooldown:Hide()
        frame.cooldown = nil
    end
    local cd = CreateFrame("Cooldown", nil, frame.iconContainer, "CooldownFrameTemplate")
    cd:SetSize(40, 40)
    cd:SetPoint("CENTER")
    cd:SetReverse(true)
    cd:SetDrawEdge(true)
    if cd.SetHideCountdownNumbers then
        cd:SetHideCountdownNumbers(false)
    end
    frame.cooldown = cd

    -- Show everything immediately
    frame.iconContainer:Show()
    frame.cooldown:Show()
    frame:Show()
    __testActive = true

    -- Set cooldown immediately with no delay
    if frame.cooldown and frame.cooldown.SetCooldown then
        frame.cooldown:Clear()
        frame.cooldown:SetCooldown(GetTime(), 10)

        local function RefreshTestCooldown()
            if not __testActive then return end
            frame.cooldown:Clear()
            frame.cooldown:SetCooldown(GetTime(), 10)
        end

        if __testTimer then __testTimer:Cancel() end
        __testTimer = C_Timer.NewTicker(10, RefreshTestCooldown)
    end
end

function HCA:HideTestAlert()
    __testActive = false
    if __testTimer then
        __testTimer:Cancel()
        __testTimer = nil
    end
    HideAlert()
end

function HCA:IsTestAlertActive()
    return __testActive
end
