local AC = _G.ArenaCore
if not AC then return end

local healerRangeTicker = nil
local healerRangeWarningFrame = nil
local healerRangeWarningAnim = nil
local healerRangeLastState = nil
local healerRangeTestState = nil
local healerRangeHookInstalled = nil

local function IsArenaInstance()
    local _, instanceType = IsInInstance()
    return instanceType == "arena"
end

local function EnsureHealerRangeWarningFrame()
    if healerRangeWarningFrame then return end

    local f = CreateFrame("Frame", nil, UIParent)
    f:SetFrameStrata("FULLSCREEN_DIALOG")
    f:SetFrameLevel(200)
    f:SetSize(1, 1)
    f:SetPoint("CENTER", UIParent, "CENTER", 0, 140)
    f:Hide()

    local text = f:CreateFontString(nil, "OVERLAY")
    text:SetPoint("CENTER")
    text:SetFont("Fonts\\FRIZQT__.TTF", 36, "OUTLINE")
    text:SetText("HEALER OUT OF RANGE")
    text:SetTextColor(1, 0.15, 0.15, 1)

    local ag = f:CreateAnimationGroup()
    ag:SetLooping("REPEAT")

    local a1 = ag:CreateAnimation("Translation")
    a1:SetOrder(1)
    a1:SetDuration(0.06)
    a1:SetOffset(14, 0)
    a1:SetSmoothing("NONE")

    local a2 = ag:CreateAnimation("Translation")
    a2:SetOrder(2)
    a2:SetDuration(0.06)
    a2:SetOffset(-28, 0)
    a2:SetSmoothing("NONE")

    local a3 = ag:CreateAnimation("Translation")
    a3:SetOrder(3)
    a3:SetDuration(0.06)
    a3:SetOffset(14, 0)
    a3:SetSmoothing("NONE")

    healerRangeWarningFrame = f
    healerRangeWarningAnim = ag
end

local function ShowHealerOutOfRangeWarning(shouldShow)
    EnsureHealerRangeWarningFrame()

    if shouldShow then
        if not healerRangeWarningFrame:IsShown() then
            healerRangeWarningFrame:Show()
        end
        if healerRangeWarningAnim and not healerRangeWarningAnim:IsPlaying() then
            healerRangeWarningAnim:Play()
        end
    else
        if healerRangeWarningAnim and healerRangeWarningAnim:IsPlaying() then
            healerRangeWarningAnim:Stop()
        end
        if healerRangeWarningFrame and healerRangeWarningFrame:IsShown() then
            healerRangeWarningFrame:Hide()
        end
    end
end

local function IsHealerOutOfRange()
    local ok, result = pcall(function()
        if not IsInGroup() then return false end
        for i = 1, 4 do
            local unit = "party" .. i
            if UnitExists(unit) and UnitIsConnected(unit)
               and not UnitIsDeadOrGhost(unit)
               and UnitGroupRolesAssigned(unit) == "HEALER" then
                local inRange, checkedRange = UnitInRange(unit)
                if checkedRange and not inRange then
                    return true
                end
                return false
            end
        end
        return false
    end)
    if ok then return result end
    return nil
end

local function EnsureHealerRangeFadeHook()
    if healerRangeHookInstalled ~= nil then
        return healerRangeHookInstalled
    end

    if type(_G.CompactUnitFrame_UpdateInRange) ~= "function" then
        healerRangeHookInstalled = false
        return false
    end

    healerRangeHookInstalled = true
    hooksecurefunc("CompactUnitFrame_UpdateInRange", function(frame)
        local ok = pcall(function()
            if healerRangeTestState then
                return
            end

            local db = AC.DB and AC.DB.profile and AC.DB.profile.moreGoodies and AC.DB.profile.moreGoodies.partyClassSpecs
            local enabled = db and db.showHealerIcon
            if not enabled or not IsArenaInstance() then
                ShowHealerOutOfRangeWarning(false)
                healerRangeLastState = nil
                return
            end

            if not frame or not frame.displayedUnit then
                return
            end

            if not UnitExists(frame.displayedUnit) or not UnitIsConnected(frame.displayedUnit) then
                return
            end

            if UnitIsUnit(frame.displayedUnit, "player") then
                return
            end

            local okIsHealer, playerIsHealer = pcall(function()
                return UnitGroupRolesAssigned("player") == "HEALER"
            end)
            if okIsHealer and playerIsHealer then
                ShowHealerOutOfRangeWarning(false)
                healerRangeLastState = nil
                return
            end

            if UnitGroupRolesAssigned(frame.displayedUnit) ~= "HEALER" then
                return
            end

            local shouldShow = frame.outOfRange == true
            if healerRangeLastState ~= shouldShow then
                healerRangeLastState = shouldShow
                ShowHealerOutOfRangeWarning(shouldShow)
            end
        end)

        if not ok then
            return
        end
    end)

    return true
end

function AC:EnsureHealerOutOfRangeWarning()
    local db = AC.DB and AC.DB.profile and AC.DB.profile.moreGoodies and AC.DB.profile.moreGoodies.partyClassSpecs

    local enabled = db and db.showHealerIcon
    if not enabled or not IsArenaInstance() then
        if healerRangeTicker then
            healerRangeTicker:Cancel()
            healerRangeTicker = nil
        end
        healerRangeLastState = nil
        ShowHealerOutOfRangeWarning(false)
        return
    end

    local okIsHealer, playerIsHealer = pcall(function()
        return UnitGroupRolesAssigned("player") == "HEALER"
    end)
    if okIsHealer and playerIsHealer then
        if healerRangeTicker then
            healerRangeTicker:Cancel()
            healerRangeTicker = nil
        end
        healerRangeLastState = nil
        ShowHealerOutOfRangeWarning(false)
        return
    end

    local hookOk = EnsureHealerRangeFadeHook()
    if hookOk then
        if healerRangeTicker then
            healerRangeTicker:Cancel()
            healerRangeTicker = nil
        end
        return
    end

    if healerRangeTicker then
        return
    end

    healerRangeTicker = C_Timer.NewTicker(0.2, function()
        if not IsArenaInstance() then
            AC:EnsureHealerOutOfRangeWarning()
            return
        end

        local shouldShow = IsHealerOutOfRange()
        if shouldShow == nil then shouldShow = false end

        if healerRangeLastState ~= shouldShow then
            healerRangeLastState = shouldShow
            ShowHealerOutOfRangeWarning(shouldShow)
        end
    end)
end

function AC:ToggleHealerOutOfRangeWarningTest()
    healerRangeTestState = not healerRangeTestState
    ShowHealerOutOfRangeWarning(healerRangeTestState)
    return healerRangeTestState
end
