AiB_Cursor = {}
local Cursor = AiB_Cursor 

local TrackerFrame = CreateFrame("Frame", "AiB_Cursor_TrackerFrame", UIParent)
-- Mache TrackerFrame global verfügbar
Cursor.TrackerFrame = TrackerFrame

-- Setup OnUpdate sofort
TrackerFrame:SetScript("OnUpdate", function(self, elapsed)
    if not AiB_Cursor or not AiB_Cursor.OnUpdate then return end
    AiB_Cursor:OnUpdate(elapsed)
end)
TrackerFrame:Show()
local LoaderFrame = CreateFrame("Frame")

local GCD_DURATION = 1.5
local GCD_SPELL_ID = 61304 
local _, _, _, interfaceVersion = GetBuildInfo()
local CURRENT_API = interfaceVersion
Cursor.GCDCooldownFrame = nil
Cursor.GCDBackgroundFrame = nil
Cursor.CastFrame = nil
Cursor.CastBackgroundFrame = nil
Cursor.HealthFrame = nil
Cursor.HealthBackgroundFrame = nil
Cursor.PowerFrame = nil

Cursor.currentGroupScale = 1.0 
Cursor.lastGCDTime = 0 
Cursor.isGCDAnimating = false 
Cursor.isCasting = false
Cursor.lastHealthPercent = 1.0
Cursor.lastPowerPercent = 1.0

Cursor.trailElements = {}
Cursor.trailActive = {}
Cursor.trailTimer = 0
Cursor.trailLastX = 0
Cursor.trailLastY = 0

Cursor.lastShiftState = false
Cursor.lastCtrlState = false
Cursor.lastAltState = false

Cursor.pingTimer = 0
Cursor.isPingAnimating = false
Cursor.pingDuration = 0.5
Cursor.pingStartSize = 250
Cursor.pingEndSize = 70

Cursor.crosshairTimer = 0
Cursor.isCrosshairAnimating = false
Cursor.crosshairDuration = 1.5
Cursor.crosshairGap = 35 -- Radius of the ring (70/2)

Cursor.defaults = {
    scale = 1.0,
    innerRing = "GCD",
    mainRing = "Main Ring",
    outerRing = "Cast",
    usePowerColors = false,
    
    -- Color modes: "default", "class", or "custom"
    reticleColorMode = "default",
    reticleCustomColor = {r = 1.0, g = 1.0, b = 1.0},
    mainRingColorMode = "default",
    mainRingCustomColor = {r = 1.0, g = 1.0, b = 1.0},
    gcdColorMode = "default",
    gcdCustomColor = {r = 1.0, g = 1.0, b = 1.0},
    castColorMode = "default",
    castCustomColor = {r = 1.0, g = 1.0, b = 1.0},
    healthColorMode = "default",
    healthCustomColor = {r = 1.0, g = 1.0, b = 1.0},
    healthColorLock = false,  
    trailColorMode = "default",
    trailCustomColor = {r = 1.0, g = 1.0, b = 1.0},
    powerColorMode = "default",
    powerCustomColor = {r = 1.0, g = 1.0, b = 1.0},
    
    -- Legacy fields (kept for backwards compatibility)
    useMainRingClassColor = false,
    useGCDClassColor = false,
    useCastClassColor = false,
    useReticleClassColor = false,
    
    enableTrail = false,
    trailUseClassColor = false,
    trailDuration = 0.5,
    trailDensity = 0.005,
    trailScale = 1.0,
    trailMinMovement = 0.5,
    showOnlyInCombat = false,
    shiftAction = "None",
    ctrlAction = "None",
    altAction = "None",
    reticle = "Dot",
    reticleScale = 1.5,
    transparency = 1.0,
    
    -- High Contrast Ring settings
    highContrastOuterThickness = 2,
    highContrastOuterColor = {r = 0.0, g = 0.0, b = 0.0},
    highContrastOuterColorMode = "default",
    highContrastInnerThickness = -4,
    highContrastInnerColor = {r = 1.0, g = 1.0, b = 1.0},
    highContrastInnerColorMode = "default",
    
    -- Seasonal Effect settings
    seasonalEffectStyle = "Candy Cane",
    seasonalParticleType = "Snowflakes",
    
    -- Cast/GCD Animation settings
    gcdFillDrain = "fill",               -- "drain" or "fill"
    castFillDrain = "fill",              -- "drain" or "fill"
    gcdRotation = 12,                    -- 1-12 (clock position, 12 = 12 o'clock)
    castRotation = 12,                   -- 1-12 (clock position)
}

Cursor.ringOptions = {
    "None",
    "Main Ring",
    "Main Ring + GCD",
    "Main Ring + Cast",
    "Cast",
    "GCD",
    "Health and Power",
    "Health",
    "Power",
    "High Contrast Ring",
}

Cursor.modifierOptions = {
    "None",
    "Show Rings",
    "Ping with ring",
    "Ping with area",
    "Ping with crosshair",
    "Show Crosshair",
}

Cursor.reticleOptions = {
    "Dot",
    "Chevron",
    "Crosshair",
    "Diamond",
    "Flatline",
    "Star",
    "Ring",
    "Tech Arrow",
    "X",
    "No Reticle",
}

Cursor.reticleTextures = {
    ["Dot"] = { path = "Interface\\AddOns\\aib\\textures\\cursor\\Reticle_Dot", scale = 0.5 },
    ["Chevron"] = { path = "uitools-icon-chevron-down", scale = 1.0, isAtlas = true },
    ["Crosshair"] = { path = "uitools-icon-plus", scale = 1.0, isAtlas = true },
    ["Diamond"] = { path = "UF-SoulShard-FX-FrameGlow", scale = 1.0, isAtlas = true },
    ["Flatline"] = { path = "uitools-icon-minus", scale = 1.0, isAtlas = true },
    ["Star"] = { path = "AftLevelup-WhiteStarBurst", scale = 2.0, isAtlas = true },
    ["Ring"] = { path = "Interface\\AddOns\\aib\\textures\\cursor\\Reticle_Circle", scale = 1.0 },
    ["Tech Arrow"] = { path = "ProgLan-w-4", scale = 1.0, isAtlas = true }, -- Assuming Atlas for now
    ["X"] = { path = "uitools-icon-close", scale = 1.0, isAtlas = true },
    ["No Reticle"] = { path = nil, scale = 1.0 },
}

function Cursor:GetClassColor(ringType)
    local colorMode = "default"
    local customColor = nil
    
    if ringType == "main" then
        colorMode = AiB_CursorConfig.mainRingColorMode or "default"
        customColor = AiB_CursorConfig.mainRingCustomColor
    elseif ringType == "gcd" then
        colorMode = AiB_CursorConfig.gcdColorMode or "default"
        customColor = AiB_CursorConfig.gcdCustomColor
    elseif ringType == "cast" then
        colorMode = AiB_CursorConfig.castColorMode or "default"
        customColor = AiB_CursorConfig.castCustomColor
    elseif ringType == "reticle" then
        colorMode = AiB_CursorConfig.reticleColorMode or "default"
        customColor = AiB_CursorConfig.reticleCustomColor
    elseif ringType == "trail" then
        colorMode = AiB_CursorConfig.trailColorMode or "default"
        customColor = (AiB_CursorConfig.colors and AiB_CursorConfig.colors.trail) or AiB_CursorConfig.trailCustomColor
    elseif ringType == "power" then
        colorMode = AiB_CursorConfig.powerColorMode or "default"
        customColor = AiB_CursorConfig.powerCustomColor
    end
    
    -- Return custom color if mode is custom
    if colorMode == "custom" and customColor then
        return customColor.r or 1.0, customColor.g or 1.0, customColor.b or 1.0
    end
    
    -- Return power type color if mode is "power" (special case for power ring)
    if colorMode == "power" and ringType == "power" then
        -- This will be handled by UpdatePowerRing function
        return nil, nil, nil
    end
    
    -- Return class color if mode is class
    if colorMode == "class" then
        local _, class = UnitClass("player")
        local classColor = C_ClassColor.GetClassColor(class)
        if classColor then
            return classColor.r, classColor.g, classColor.b
        end
    end

    -- Return default color
    -- Power ring default is cyan blue (original color), others are white
    if ringType == "power" then
        return 0.0, 0.5, 1.0  -- Cyan blue for power (original default)
    else
        return 1.0, 1.0, 1.0  -- White for others
    end
end

function Cursor:ClockToRadians(clockPosition)
    -- Convert clock position (1-12) to radians for SetRotation
    -- 12 = 12 o'clock (top), 3 = 3 o'clock (right), 6 = 6 o'clock (bottom), 9 = 9 o'clock (left)
    -- WoW rotation: 0 radians = 12 o'clock
    local position = (clockPosition == 12) and 0 or clockPosition
    return (position * math.pi / 6) -- Each hour = 30 degrees = π/6 radians
end






function Cursor:UpdateRingColors()
    -- Check which configurations are selected
    local hasMainRingPlusGCD = false
    local hasMainRingPlusCast = false
    
    local slots = {
        {config = AiB_CursorConfig.innerRing},
        {config = AiB_CursorConfig.mainRing},
        {config = AiB_CursorConfig.outerRing},
    }
    
    for _, slot in ipairs(slots) do
        if slot.config == "Main Ring + GCD" then
            hasMainRingPlusGCD = true
        end
        if slot.config == "Main Ring + Cast" then
            hasMainRingPlusCast = true
        end
    end
    
    -- GCD: Use gray if "Main Ring + GCD" is selected without class colors
    -- GCD: Use gray if "Main Ring + GCD" is selected AND mode is "default"
    if Cursor.GCDCooldownFrame then
        local gcdMode = AiB_CursorConfig.gcdColorMode or "default"
        if hasMainRingPlusGCD and gcdMode == "default" then
            -- Gray for contrast with white Main Ring
            Cursor.GCDCooldownFrame:SetSwipeColor(0.4, 0.4, 0.4, 1.0)
        else
            -- Use class color (white or class color or custom)
            local r, g, b = Cursor:GetClassColor("gcd")
            Cursor.GCDCooldownFrame:SetSwipeColor(r, g, b, 1.0)
        end
    end

    -- Cast: Use gray if "Main Ring + Cast" is selected AND mode is "default"
    if Cursor.CastFrame then
        local castMode = AiB_CursorConfig.castColorMode or "default"
        if hasMainRingPlusCast and castMode == "default" then
            -- Gray for contrast with white Main Ring
            Cursor.CastFrame:SetSwipeColor(0.4, 0.4, 0.4, 1.0)
        else
            -- Use class color (white or class color or custom)
            local r, g, b = Cursor:GetClassColor("cast")
            Cursor.CastFrame:SetSwipeColor(r, g, b, 1.0)
        end
    end

    -- Main Ring: Always use class color (white or class color)
    if AiB_Cursor_CursorFrame and AiB_Cursor_CursorFrame.MainRing then
        local r, g, b = Cursor:GetClassColor("main")
        AiB_Cursor_CursorFrame.MainRing:SetVertexColor(r, g, b, 1.0)
    end
end

function Cursor:UpdateReticle()
    if not AiB_Cursor_CursorFrame or not AiB_Cursor_CursorFrame.Reticle then return end
    
    local reticleName = AiB_CursorConfig.reticle or "Dot"
    local reticleInfo = Cursor.reticleTextures[reticleName]
    
    if not reticleInfo or not reticleInfo.path then
        -- No Reticle or invalid
        AiB_Cursor_CursorFrame.Reticle:Hide()
    else
        AiB_Cursor_CursorFrame.Reticle:Show()
        
        if reticleInfo.isAtlas then
            AiB_Cursor_CursorFrame.Reticle:SetAtlas(reticleInfo.path)
        else
            AiB_Cursor_CursorFrame.Reticle:SetTexture(reticleInfo.path)
        end
        
        -- Apply scale
        local globalScale = AiB_CursorConfig.reticleScale or 1.0
        AiB_Cursor_CursorFrame.Reticle:SetScale(reticleInfo.scale * globalScale)
        
        -- Apply color using GetClassColor
        local r, g, b = Cursor:GetClassColor("reticle")
        AiB_Cursor_CursorFrame.Reticle:SetVertexColor(r, g, b, 1.0)
    end
end

function Cursor:SetGroupScale(scale)
    if type(scale) == "number" and scale > 0 then
        Cursor.currentGroupScale = scale
        AiB_Cursor_CursorFrame:SetScale(scale)
    end
end

function Cursor:CreateHighContrastRing(size)
    -- Initialize High Contrast Ring frames if they don't exist
    if not Cursor.HighContrastRings then
        Cursor.HighContrastRings = {}
    end
    
    -- Create or reuse ring for this size
    local ringKey = "ring_" .. size
    local ring = Cursor.HighContrastRings[ringKey]
    
    if not ring then
        -- Create the two-ring structure
        ring = {}
        
        -- Outer Half: Larger ring (for visibility on light backgrounds)
        local outerHalf = AiB_Cursor_CursorFrame:CreateTexture(nil, "ARTWORK")
        outerHalf:SetTexture("Interface\\AddOns\\aib\\textures\\cursor\\Ring_Main")
        outerHalf:SetPoint("CENTER", AiB_Cursor_CursorFrame, "CENTER")
        outerHalf:SetDrawLayer("ARTWORK", 1)
        ring.outerHalf = outerHalf
        
        -- Inner Half: Smaller ring (for visibility on dark backgrounds)
        local innerHalf = AiB_Cursor_CursorFrame:CreateTexture(nil, "ARTWORK")
        innerHalf:SetTexture("Interface\\AddOns\\aib\\textures\\cursor\\Ring_Main")
        innerHalf:SetPoint("CENTER", AiB_Cursor_CursorFrame, "CENTER")
        innerHalf:SetDrawLayer("ARTWORK", 2)
        ring.innerHalf = innerHalf
        
        Cursor.HighContrastRings[ringKey] = ring
    end
    
    -- Get colors based on color mode
    local function GetHighContrastColor(colorMode, customColor, defaultColor)
        if colorMode == "class" then
            local _, class = UnitClass("player")
            if class then
                local classColor = RAID_CLASS_COLORS[class]
                if classColor then
                    return classColor.r, classColor.g, classColor.b
                end
            end
        elseif colorMode == "custom" then
            return customColor.r, customColor.g, customColor.b
        end
        -- default mode
        return defaultColor.r, defaultColor.g, defaultColor.b
    end
    
    -- Apply colors and thickness from config
    local outerColorMode = AiB_CursorConfig.highContrastOuterColorMode or "default"
    local outerCustomColor = AiB_CursorConfig.highContrastOuterColor or {r = 0.0, g = 0.0, b = 0.0}
    local outerDefaultColor = {r = 0.0, g = 0.0, b = 0.0}  -- Black
    local outerThickness = AiB_CursorConfig.highContrastOuterThickness or 2
    
    local innerColorMode = AiB_CursorConfig.highContrastInnerColorMode or "default"
    local innerCustomColor = AiB_CursorConfig.highContrastInnerColor or {r = 1.0, g = 1.0, b = 1.0}
    local innerDefaultColor = {r = 1.0, g = 1.0, b = 1.0}  -- White
    local innerThickness = AiB_CursorConfig.highContrastInnerThickness or -4
    
    -- Calculate sizes
    -- Outer half is the base size plus outer thickness
    local outerSize = size + (outerThickness * 2)
    -- Inner half also grows with thickness (same direction as outer)
    local innerSize = size + (innerThickness * 2)
    
    -- Apply sizes
    ring.outerHalf:SetSize(outerSize, outerSize)
    ring.innerHalf:SetSize(innerSize, innerSize)
    
    -- Apply colors using color mode system
    local outerR, outerG, outerB = GetHighContrastColor(outerColorMode, outerCustomColor, outerDefaultColor)
    local innerR, innerG, innerB = GetHighContrastColor(innerColorMode, innerCustomColor, innerDefaultColor)
    
    ring.outerHalf:SetVertexColor(outerR, outerG, outerB, 1.0)
    ring.innerHalf:SetVertexColor(innerR, innerG, innerB, 1.0)
    
    -- Show the ring
    ring.outerHalf:Show()
    ring.innerHalf:Show()
    
    -- Hide other rings of different sizes
    for key, otherRing in pairs(Cursor.HighContrastRings) do
        if key ~= ringKey then
            if otherRing.outerHalf then otherRing.outerHalf:Hide() end
            if otherRing.innerHalf then otherRing.innerHalf:Hide() end
            -- Hide old sandwich layers if they exist
            if otherRing.outerBorder then otherRing.outerBorder:Hide() end
            if otherRing.centerRing then otherRing.centerRing:Hide() end
            if otherRing.innerBorder then otherRing.innerBorder:Hide() end
        end
    end
end

function Cursor:InitializeTrail()
    for i = 1, 300 do
        local texture = UIParent:CreateTexture(nil, "ARTWORK")
        texture:SetTexture("Interface\\AddOns\\aib\\textures\\cursor\\reticle_dot")
        texture:SetBlendMode("ADD")
        texture:Hide()
        Cursor.trailElements[i] = texture
    end
end

-- Seasonal Particle System
Cursor.particlePool = {}
Cursor.activeParticles = {}
Cursor.maxParticles = 100
Cursor.particleTimer = 0

function Cursor:InitializeSeasonalParticles()
    -- Pre-create particle pool
    for i = 1, Cursor.maxParticles do
        local particle = UIParent:CreateTexture(nil, "ARTWORK")
        particle:SetBlendMode("ADD")
        particle:Hide()
        table.insert(Cursor.particlePool, particle)
    end
end

function Cursor:GetParticleAtlasForStyle(style)
    -- Particle types: Snowflakes (drift down), Sparkles (burst out), Both, None
    local configs = {}
    local particleType = AiB_CursorConfig.seasonalParticleType or "Snowflakes"
    
    if particleType == "None" then
        -- No particles
        return configs
    elseif particleType == "Snowflakes" then
        -- Snowflakes: drift down gently (increased lifetime for continuity)
        table.insert(configs, {atlas = "Adventures-Buff-Heal-Burst", tint = {1.0, 1.0, 1.0}, size = 24, lifetime = 2.5, drift = true})
    elseif particleType == "Sparkles" then
        -- Sparkles: burst outward (increased lifetime for continuity)
        table.insert(configs, {atlas = "Adventures-Buff-Heal-Burst", tint = {1.0, 1.0, 1.0}, size = 20, lifetime = 1.5, burst = true})
    elseif particleType == "Both" then
        -- Both: mix of snowflakes and sparkles
        table.insert(configs, {atlas = "Adventures-Buff-Heal-Burst", tint = {1.0, 1.0, 1.0}, size = 24, lifetime = 2.5, drift = true})
        table.insert(configs, {atlas = "Adventures-Buff-Heal-Burst", tint = {1.0, 1.0, 1.0}, size = 20, lifetime = 1.5, burst = true})
    end
    
    return configs
end

function Cursor:GetTrailColorForStyle(style)
    -- Returns color for trail based on style
    -- Candy Cane: alternates between red and white
    -- Christmas Lights: cycles through red, green, gold
    -- None: default white
    
    if style == "None" then
        -- Default white
        return 1.0, 1.0, 1.0
    elseif style == "Candy Cane" then
        -- Alternate between red and white
        Cursor.candyCaneToggle = not Cursor.candyCaneToggle
        if Cursor.candyCaneToggle then
            return 1.0, 0.0, 0.0 -- Red
        else
            return 1.0, 1.0, 1.0 -- White
        end
    elseif style == "Christmas Lights" then
        -- Cycle through colors: red, green, gold, white, blue
        Cursor.lightsIndex = (Cursor.lightsIndex or 0) + 1
        if Cursor.lightsIndex > 5 then Cursor.lightsIndex = 1 end
        
        if Cursor.lightsIndex == 1 then
            return 1.0, 0.0, 0.0 -- Red
        elseif Cursor.lightsIndex == 2 then
            return 0.0, 1.0, 0.0 -- Green
        elseif Cursor.lightsIndex == 3 then
            return 1.0, 0.84, 0.0 -- Gold
        elseif Cursor.lightsIndex == 4 then
            return 1.0, 1.0, 1.0 -- White
        else
            return 0.3, 0.7, 1.0 -- Blue
        end
    end
    
    -- Default white
    return 1.0, 1.0, 1.0
end

function Cursor:CreateSeasonalParticle(x, y)
    if #Cursor.particlePool == 0 then return end
    if #Cursor.activeParticles >= Cursor.maxParticles then return end
    
    local style = AiB_CursorConfig.seasonalEffectStyle or "Candy Cane"
    local particleConfigs = Cursor:GetParticleAtlasForStyle(style)
    
    -- If no particle configs (None selected), don't create particles
    if #particleConfigs == 0 then return end
    
    -- Select random particle config from available options
    local selectedConfig = particleConfigs[math.random(#particleConfigs)]
    
    local particle = table.remove(Cursor.particlePool)
    table.insert(Cursor.activeParticles, particle)
    
    -- Set atlas texture
    particle:SetAtlas(selectedConfig.atlas)
    
    -- Set color
    local tint = selectedConfig.tint
    particle:SetVertexColor(tint[1], tint[2], tint[3], 1.0)
    
    -- Set size with random variation
    local sizeVariation = 0.7 + (math.random() * 0.6) -- 0.7 to 1.3
    local size = selectedConfig.size * sizeVariation
    particle:SetSize(size, size)
    
    -- Position
    local uiScale = UIParent:GetEffectiveScale()
    particle.x = x / uiScale
    particle.y = y / uiScale
    particle:SetPoint("CENTER", UIParent, "BOTTOMLEFT", particle.x, particle.y)
    
    -- Lifetime
    particle.lifetime = selectedConfig.lifetime
    particle.maxLifetime = selectedConfig.lifetime
    
    -- Movement properties
    if selectedConfig.drift then
        -- Snowflake: gentle downward drift with wobble
        particle.vx = (math.random() - 0.5) * 20 -- Horizontal wobble
        particle.vy = -30 - (math.random() * 20) -- Downward drift
        particle.rotation = math.random() * 360
        particle.rotationSpeed = (math.random() - 0.5) * 90 -- degrees per second
    elseif selectedConfig.burst then
        -- Sparkle: slight outward burst
        local angle = math.random() * math.pi * 2
        local speed = 10 + (math.random() * 20)
        particle.vx = math.cos(angle) * speed
        particle.vy = math.sin(angle) * speed
        particle.rotation = math.random() * 360
        particle.rotationSpeed = (math.random() - 0.5) * 180
    elseif selectedConfig.rotate then
        -- Candy cane: rotating in place
        particle.vx = 0
        particle.vy = -10 -- Slight downward
        particle.rotation = math.random() * 360
        particle.rotationSpeed = 180 + (math.random() * 180)
    elseif selectedConfig.pulse then
        -- Christmas lights: pulsing
        particle.vx = 0
        particle.vy = 0
        particle.rotation = 0
        particle.rotationSpeed = 0
        particle.pulsePhase = math.random() * math.pi * 2
    else
        particle.vx = 0
        particle.vy = 0
        particle.rotation = 0
        particle.rotationSpeed = 0
    end
    
    particle.config = selectedConfig
    particle:SetAlpha(1.0)
    particle:Show()
end

function Cursor:UpdateSeasonalParticles(elapsed)
    -- Update existing particles
    for i = #Cursor.activeParticles, 1, -1 do
        local particle = Cursor.activeParticles[i]
        particle.lifetime = particle.lifetime - elapsed
        
        if particle.lifetime <= 0 then
            -- Return to pool
            particle:Hide()
            table.insert(Cursor.particlePool, table.remove(Cursor.activeParticles, i))
        else
            -- Update position
            particle.x = particle.x + (particle.vx * elapsed)
            particle.y = particle.y + (particle.vy * elapsed)
            particle:SetPoint("CENTER", UIParent, "BOTTOMLEFT", particle.x, particle.y)
            
            -- Update rotation
            if particle.rotationSpeed and particle.rotationSpeed ~= 0 then
                particle.rotation = particle.rotation + (particle.rotationSpeed * elapsed)
                -- Note: WoW textures don't have SetRotation, so we'll skip actual rotation
                -- The visual variety comes from movement and fading
            end
            
            -- Update alpha (fade out)
            local progress = particle.lifetime / particle.maxLifetime
            local alpha = progress
            
            -- Pulsing effect for Christmas lights
            if particle.config.pulse then
                particle.pulsePhase = particle.pulsePhase + (elapsed * 3)
                local pulseAlpha = 0.6 + (math.sin(particle.pulsePhase) * 0.4)
                alpha = alpha * pulseAlpha
            end
            
            particle:SetAlpha(alpha)
        end
    end
end

function Cursor:UpdateTrail(elapsed)
    -- Check if trail should be visible based on cursor visibility
    local shouldShowTrail = AiB_CursorConfig.enableTrail and AiB_Cursor_CursorFrame and AiB_Cursor_CursorFrame:IsShown()
    
    if shouldShowTrail then
        local cursorX, cursorY = GetCursorPosition()
        local uiScale = UIParent:GetEffectiveScale()

        local x = cursorX - Cursor.trailLastX
        local y = cursorY - Cursor.trailLastY
        local movement = math.sqrt(x * x + y * y)

        local minMovement = AiB_CursorConfig.trailMinMovement or 0.5
        local density = AiB_CursorConfig.trailDensity or 0.008

        Cursor.trailTimer = Cursor.trailTimer + elapsed

        if Cursor.trailTimer >= density and movement >= minMovement and #Cursor.trailElements > 0 then
            Cursor.trailTimer = 0

            -- Check if we should use seasonal effects
            local trailColorMode = AiB_CursorConfig.trailColorMode or "default"
            
            if trailColorMode == "seasonal" then
                local style = AiB_CursorConfig.seasonalEffectStyle or "Candy Cane"
                
                -- Spawn more particles for continuous effect (3-5 instead of 1-2)
                local particleCount = math.random(3, 5)
                for i = 1, particleCount do
                    Cursor:CreateSeasonalParticle(cursorX, cursorY)
                end
                
                -- Only show colored trail if style is NOT None
                if style ~= "None" then
                    local element = table.remove(Cursor.trailElements)
                    table.insert(Cursor.trailActive, element)

                    element.duration = AiB_CursorConfig.trailDuration or 0.4
                    element.x = cursorX / uiScale
                    element.y = cursorY / uiScale

                    -- Get color based on style
                    local r, g, b = Cursor:GetTrailColorForStyle(style)

                    element:SetVertexColor(r, g, b, 1.0)
                    local baseSize = 50 * (AiB_CursorConfig.trailScale or 1.0)
                    element:SetSize(baseSize, baseSize)
                    element:SetPoint("CENTER", UIParent, "BOTTOMLEFT", element.x, element.y)
                    element:SetAlpha(0.5)  -- Start at 50% alpha so colors are more visible
                    element:Show()
                end
            else
                -- Regular trail behavior
                local element = table.remove(Cursor.trailElements)
                table.insert(Cursor.trailActive, element)

                element.duration = AiB_CursorConfig.trailDuration or 0.4
                element.x = cursorX / uiScale
                element.y = cursorY / uiScale

                -- Use GetClassColor for trail color
                local r, g, b = Cursor:GetClassColor("trail")

                element:SetVertexColor(r, g, b, 1.0)
                local baseSize = 50 * (AiB_CursorConfig.trailScale or 1.0)
                element:SetSize(baseSize, baseSize)
                element:SetPoint("CENTER", UIParent, "BOTTOMLEFT", element.x, element.y)
                element:SetAlpha(1.0)
                element:Show()
            end

            Cursor.trailLastX = cursorX
            Cursor.trailLastY = cursorY
        end
        
        -- Update seasonal particles
        Cursor:UpdateSeasonalParticles(elapsed)
    else
        for i = #Cursor.trailActive, 1, -1 do
            local element = Cursor.trailActive[i]
            element:Hide()
            table.insert(Cursor.trailElements, table.remove(Cursor.trailActive, i))
        end
        
        -- Hide all seasonal particles when trail is disabled
        for i = #Cursor.activeParticles, 1, -1 do
            local particle = Cursor.activeParticles[i]
            particle:Hide()
            table.insert(Cursor.particlePool, table.remove(Cursor.activeParticles, i))
        end
    end

    for i = #Cursor.trailActive, 1, -1 do
        local element = Cursor.trailActive[i]
        element.duration = element.duration - elapsed

        if element.duration <= 0 then
            element:Hide()
            table.insert(Cursor.trailElements, table.remove(Cursor.trailActive, i))
        else
            local progress = element.duration / (AiB_CursorConfig.trailDuration or 0.4)
            progress = math.min(1.0, math.max(0.0, progress))
            local baseSize = 50 * (AiB_CursorConfig.trailScale or 1.0)
            local size = math.max(5, baseSize * progress)
            element:SetSize(size, size)
            element:SetAlpha(progress)
            element:SetPoint("CENTER", UIParent, "BOTTOMLEFT", element.x, element.y)
        end
    end
end

function Cursor:OnUpdate(elapsed)
    -- v2.1.0.0: AceDB wird erst in ADDON_LOADED gesetzt – vor dem ersten
    -- Login-Event kann AiB_CursorConfig noch nil sein.
    if not AiB_CursorConfig then return end
    local cursorX, cursorY = GetCursorPosition()
    local uiScale = UIParent:GetScale()
    local groupScale = Cursor.currentGroupScale

    local correctedX = (cursorX / uiScale) / groupScale
    local correctedY = (cursorY / uiScale) / groupScale

    AiB_Cursor_CursorFrame:ClearAllPoints()
    AiB_Cursor_CursorFrame:SetPoint("CENTER", UIParent, "BOTTOMLEFT", correctedX, correctedY)

    Cursor:UpdateTrail(elapsed)

    -- Modifier Key Logic
    local shiftDown = IsShiftKeyDown()
    local ctrlDown = IsControlKeyDown()
    local altDown = IsAltKeyDown()

    -- Check for Ping/Crosshair triggers (OnPress)
    if shiftDown and not Cursor.lastShiftState then
        if AiB_CursorConfig.shiftAction == "Ping with ring" then Cursor:PlayPingAnimation("Interface\\AddOns\\aib\\textures\\cursor\\Ring_Main")
        elseif AiB_CursorConfig.shiftAction == "Ping with area" then Cursor:PlayPingAnimation("Interface\\AddOns\\aib\\textures\\cursor\\Reticle_Dot")
        elseif AiB_CursorConfig.shiftAction == "Ping with crosshair" then Cursor:PlayCrosshairAnimation() end
    end
    if ctrlDown and not Cursor.lastCtrlState then
        if AiB_CursorConfig.ctrlAction == "Ping with ring" then Cursor:PlayPingAnimation("Interface\\AddOns\\aib\\textures\\cursor\\Ring_Main")
        elseif AiB_CursorConfig.ctrlAction == "Ping with area" then Cursor:PlayPingAnimation("Interface\\AddOns\\aib\\textures\\cursor\\Reticle_Dot")
        elseif AiB_CursorConfig.ctrlAction == "Ping with crosshair" then Cursor:PlayCrosshairAnimation() end
    end
    if altDown and not Cursor.lastAltState then
        if AiB_CursorConfig.altAction == "Ping with ring" then Cursor:PlayPingAnimation("Interface\\AddOns\\aib\\textures\\cursor\\Ring_Main")
        elseif AiB_CursorConfig.altAction == "Ping with area" then Cursor:PlayPingAnimation("Interface\\AddOns\\aib\\textures\\cursor\\Reticle_Dot")
        elseif AiB_CursorConfig.altAction == "Ping with crosshair" then Cursor:PlayCrosshairAnimation() end
    end

    -- Check for "Show Crosshair" (OnHold)
    local showCrosshair = (shiftDown and AiB_CursorConfig.shiftAction == "Show Crosshair") or
                          (ctrlDown and AiB_CursorConfig.ctrlAction == "Show Crosshair") or
                          (altDown and AiB_CursorConfig.altAction == "Show Crosshair")

    if showCrosshair then
        Cursor.isCrosshairAnimating = false -- Stop animation if it was running
        Cursor.CrosshairFrame:Show()
        Cursor.CrosshairFrame:SetAlpha(1.0)
        Cursor:UpdateCrosshairPosition()
    elseif (not shiftDown and Cursor.lastShiftState and AiB_CursorConfig.shiftAction == "Show Crosshair") or
           (not ctrlDown and Cursor.lastCtrlState and AiB_CursorConfig.ctrlAction == "Show Crosshair") or
           (not altDown and Cursor.lastAltState and AiB_CursorConfig.altAction == "Show Crosshair") then
        -- Just released "Show Crosshair", trigger fade out
        Cursor:PlayCrosshairAnimation()
    end

    -- Check for Visibility triggers (OnHold)
    local showRings = false
    if shiftDown and AiB_CursorConfig.shiftAction == "Show Rings" then showRings = true end
    if ctrlDown and AiB_CursorConfig.ctrlAction == "Show Rings" then showRings = true end
    if altDown and AiB_CursorConfig.altAction == "Show Rings" then showRings = true end

    if showRings then
        Cursor:UpdateVisibility(true)
    elseif (not shiftDown and Cursor.lastShiftState and AiB_CursorConfig.shiftAction == "Show Rings") or
           (not ctrlDown and Cursor.lastCtrlState and AiB_CursorConfig.ctrlAction == "Show Rings") or
           (not altDown and Cursor.lastAltState and AiB_CursorConfig.altAction == "Show Rings") then
         -- Just released a "Show Rings" key, revert to normal visibility
         Cursor:UpdateVisibility()
    end

    Cursor.lastShiftState = shiftDown
    Cursor.lastCtrlState = ctrlDown
    Cursor.lastAltState = altDown

    -- Ping Animation Update
    if Cursor.isPingAnimating then
        Cursor.pingTimer = Cursor.pingTimer + elapsed
        if Cursor.pingTimer >= Cursor.pingDuration then
            Cursor.isPingAnimating = false
            Cursor.PingFrame:Hide()
        else
            local progress = Cursor.pingTimer / Cursor.pingDuration
            local size = Cursor.pingStartSize - ((Cursor.pingStartSize - Cursor.pingEndSize) * progress)
            local alpha = 1.0 - progress
            
            Cursor.PingFrame:SetSize(size, size)
            Cursor.PingFrame:SetAlpha(alpha)
            Cursor.PingFrame:SetPoint("CENTER", AiB_Cursor_CursorFrame, "CENTER") 
        end
    end

    -- Crosshair Animation Update
    if Cursor.isCrosshairAnimating then
        Cursor.crosshairTimer = Cursor.crosshairTimer + elapsed
        if Cursor.crosshairTimer >= Cursor.crosshairDuration then
            Cursor.isCrosshairAnimating = false
            Cursor.CrosshairFrame:Hide()
        else
            local progress = Cursor.crosshairTimer / Cursor.crosshairDuration
            local alpha = 1.0
            if progress > 0.7 then -- Fade out in last 30%
                alpha = 1.0 - ((progress - 0.7) / 0.3)
            end
            
            Cursor.CrosshairFrame:SetAlpha(alpha)
            
            Cursor:UpdateCrosshairPosition()
        end
    end
end

function Cursor:UpdateCrosshairPosition()
    if not Cursor.CrosshairFrame then return end
    
    local gap = Cursor.crosshairGap * Cursor.currentGroupScale
    local cx, cy = GetCursorPosition()
    local scale = UIParent:GetEffectiveScale()
    cx = cx / scale
    cy = cy / scale
    
    -- Top Line
    Cursor.CrosshairFrame.Top:ClearAllPoints()
    Cursor.CrosshairFrame.Top:SetPoint("TOP", UIParent, "TOPLEFT", cx, 0)
    Cursor.CrosshairFrame.Top:SetPoint("BOTTOM", UIParent, "BOTTOMLEFT", cx, cy + gap)
    
    -- Bottom Line
    Cursor.CrosshairFrame.Bottom:ClearAllPoints()
    Cursor.CrosshairFrame.Bottom:SetPoint("BOTTOM", UIParent, "BOTTOMLEFT", cx, 0)
    Cursor.CrosshairFrame.Bottom:SetPoint("TOP", UIParent, "BOTTOMLEFT", cx, cy - gap)
    
    -- Left Line
    Cursor.CrosshairFrame.Left:ClearAllPoints()
    Cursor.CrosshairFrame.Left:SetPoint("LEFT", UIParent, "BOTTOMLEFT", 0, cy)
    Cursor.CrosshairFrame.Left:SetPoint("RIGHT", UIParent, "BOTTOMLEFT", cx - gap, cy)
    
    -- Right Line
    Cursor.CrosshairFrame.Right:ClearAllPoints()
    Cursor.CrosshairFrame.Right:SetPoint("RIGHT", UIParent, "BOTTOMRIGHT", 0, cy)
    Cursor.CrosshairFrame.Right:SetPoint("LEFT", UIParent, "BOTTOMLEFT", cx + gap, cy)
end

function Cursor:PlayPingAnimation(texturePath)
    if not Cursor.PingFrame then return end
    if texturePath then
        Cursor.PingFrame:SetTexture(texturePath)
    end
    Cursor.isPingAnimating = true
    Cursor.pingTimer = 0
    Cursor.PingFrame:SetSize(Cursor.pingStartSize, Cursor.pingStartSize)
    Cursor.PingFrame:SetAlpha(1.0)
    Cursor.PingFrame:Show()
end

function Cursor:PlayCrosshairAnimation()
    if not Cursor.CrosshairFrame then return end
    Cursor.isCrosshairAnimating = true
    Cursor.crosshairTimer = 0
    Cursor.CrosshairFrame:SetAlpha(1.0)
    Cursor.CrosshairFrame:Show()
end







function Cursor:UpdateHealthRing()
    if CURRENT_API >= 120000 then return end
    local healthFrame = Cursor.HealthFrame
    if not healthFrame then return end

    local currentHealth = UnitHealth("player")
    local maxHealth = UnitHealthMax("player")

    if maxHealth == 0 then return end

    local healthPercent = currentHealth / maxHealth
    local missingHealthPercent = 1 - healthPercent

    local r, g, b
    
    -- Check if health color is locked (always use selected color)
    local healthColorLock = AiB_CursorConfig.healthColorLock or false
    
    if healthColorLock or healthPercent > 0.70 then
        -- Use configured health color when locked or when health is high
        local healthColorMode = AiB_CursorConfig.healthColorMode or "default"
        if healthColorMode == "class" then
            local _, class = UnitClass("player")
            if class then
                local classColor = RAID_CLASS_COLORS[class]
                if classColor then
                    r, g, b = classColor.r, classColor.g, classColor.b
                else
                    r, g, b = 1.0, 1.0, 1.0  -- Fallback to white
                end
            else
                r, g, b = 1.0, 1.0, 1.0  -- Fallback to white
            end
        elseif healthColorMode == "custom" then
            local customColor = AiB_CursorConfig.healthCustomColor or {r = 1.0, g = 1.0, b = 1.0}
            r, g, b = customColor.r, customColor.g, customColor.b
        else
            -- default mode
            r, g, b = 1.0, 1.0, 1.0  -- White
        end
    elseif healthPercent > 0.50 then
        r, g, b = 1.0, 0.788, 0.302
    elseif healthPercent > 0.35 then
        r, g, b = 1.0, 0.451, 0.184
    else
        r, g, b = 0.8, 0.0, 0.02
    end

    healthFrame:SetSwipeColor(r, g, b, 0.8)

    -- Clear previous cooldown state before setting new one
    healthFrame:SetCooldown(0, 0)
    healthFrame:Clear()
    local hugeDuration = 86400
    local elapsed = missingHealthPercent * hugeDuration
    healthFrame:SetCooldown(GetTime() - elapsed, hugeDuration)
    healthFrame:Show()

    Cursor.lastHealthPercent = healthPercent
end

function Cursor:HealthEventHandler(self, event, unit)
    if unit ~= "player" then return end

    Cursor:UpdateHealthRing()
end

function Cursor:UpdatePowerRing()
    
    if CURRENT_API >= 120000 then 
        return 
    end
    
    local powerFrame = Cursor.PowerFrame
    if not powerFrame then 
        return 
    end

    local currentPower = UnitPower("player")
    local maxPower = UnitPowerMax("player")
    

    if maxPower == 0 then 
        return 
    end

    local powerPercent = currentPower / maxPower
    local missingPowerPercent = 1 - powerPercent
    

    -- Get color using GetClassColor system
    local r, g, b = Cursor:GetClassColor("power")
    
    -- If GetClassColor returned nil (power mode), use power type colors
    if not r then
        local powerType, powerToken = UnitPowerType("player")
        
        
        if powerType == 0 then
            r, g, b = 0.00, 0.00, 1.00  -- Mana
        elseif powerType == 1 then
            r, g, b = 1.00, 0.00, 0.00  -- Rage
        elseif powerType == 2 then
            r, g, b = 1.00, 0.50, 0.25  -- Focus
        elseif powerType == 3 then
            r, g, b = 1.00, 1.00, 0.00  -- Energy
        elseif powerType == 4 then
            r, g, b = 1.00, 0.96, 0.41  -- Combo Points
        elseif powerType == 5 then
            r, g, b = 0.50, 0.50, 0.50  -- Runes
        elseif powerType == 6 then
            r, g, b = 0.00, 0.82, 1.00  -- Runic Power
        elseif powerType == 7 then
            r, g, b = 0.50, 0.32, 0.55  -- Soul Shards
        elseif powerType == 8 then
            r, g, b = 0.30, 0.52, 0.90  -- Lunar Power
        elseif powerType == 9 then
            r, g, b = 0.95, 0.90, 0.60  -- Holy Power
        elseif powerType == 11 then
            r, g, b = 0.00, 0.50, 1.00  -- Maelstrom
        elseif powerType == 13 then
            r, g, b = 0.40, 0.00, 0.80  -- Insanity
        elseif powerType == 12 then
            r, g, b = 0.71, 1.00, 0.92  -- Chi
        elseif powerType == 16 then
            r, g, b = 0.10, 0.10, 0.98  -- Arcane Charges
        elseif powerType == 17 then
            r, g, b = 0.788, 0.259, 0.992  -- Fury
        elseif powerType == 18 then
            r, g, b = 1.00, 0.61, 0.00  -- Pain
        else
            r, g, b = 0.00, 0.00, 1.00  -- Default to mana blue
        end
    else
    end

    powerFrame:SetSwipeColor(r, g, b, 0.8)

    local hugeDuration = 86400
    local elapsed = missingPowerPercent * hugeDuration
    
    powerFrame:SetCooldown(GetTime() - elapsed, hugeDuration)
    powerFrame:Show()

    Cursor.lastPowerPercent = powerPercent
    
end
function Cursor:PowerEventHandler(self, event, unit)
    if unit ~= "player" then return end

    Cursor:UpdatePowerRing()
end

function Cursor:StartGCDAnimation(startTime, duration)
    if not Cursor.GCDCooldownFrame then return end
    if not Cursor.enableGCD then return end
    
    Cursor.isGCDAnimating = true
    
    -- Simple fill/drain control
    local fillDrain = AiB_CursorConfig.gcdFillDrain or "drain"
    Cursor.GCDCooldownFrame:SetReverse(fillDrain == "fill")
    
    Cursor.GCDCooldownFrame:SetCooldown(startTime, duration)
    Cursor.GCDCooldownFrame:Show()
end











function Cursor:StartCastAnimation(startTime, duration)
    if not Cursor.CastFrame then return end
    if not Cursor.enableCast then return end
    
    Cursor.isCasting = true
    
    -- Detect if this is a channel or regular cast
    local isChanneling = UnitChannelInfo("player") ~= nil
    
    -- For channels, automatically reverse the fill/drain behavior
    local fillDrain = AiB_CursorConfig.castFillDrain or "fill"
    local shouldReverse = (fillDrain == "fill")
    
    -- Invert for channels to create the opposite visual effect
    if isChanneling then
        shouldReverse = not shouldReverse
    end
    
    Cursor.CastFrame:SetReverse(shouldReverse)
    
    Cursor.CastFrame:SetCooldown(startTime, duration)
    Cursor.CastFrame:Show()
end




function Cursor:StopCastAnimation()
    if not Cursor.CastFrame then return end
    
    Cursor.isCasting = false
    Cursor.CastFrame:Clear()
    Cursor.CastFrame:Hide()
end

function Cursor:GCDCastHandler(self, event, unit, spellName, spellId)
    --if CURRENT_API >= 120000 then return end
    if GetTime() - Cursor.lastGCDTime < 0.1 then return end

    Cursor.lastGCDTime = GetTime()

    local GCDInfo = C_Spell.GetSpellCooldown(GCD_SPELL_ID)

    if GCDInfo and GCDInfo.duration > 0 then
        Cursor:StartGCDAnimation(GCDInfo.startTime, GCDInfo.duration)
    end

end

function Cursor:CastEventHandler(self, event, unit) 

    local startTime, endTime, infoValid = nil, nil, false

    if event == "UNIT_SPELLCAST_START" then
        local cName, cRank, cTarget, cStartTime, cEndTime = UnitCastingInfo("player")
        startTime, endTime = cStartTime, cEndTime
        infoValid = true

    elseif event == "UNIT_SPELLCAST_CHANNEL_START" then
        local chName, chRank, chTarget, chStartTime, chEndTime, isMoving = UnitChannelInfo("player")
        startTime, endTime = chStartTime, chEndTime
        infoValid = true
    end

    if infoValid and startTime and endTime then
        local duration = (endTime - startTime) / 1000 

        if duration > 0.1 then 
            Cursor:StartCastAnimation(startTime / 1000, duration)
        end

    elseif event == "UNIT_SPELLCAST_STOP" or event == "UNIT_SPELLCAST_CHANNEL_STOP" then
        Cursor:StopCastAnimation()
    end
end

function Cursor:UpdateVisibility(forceState)
    if not AiB_Cursor_CursorFrame then return end
    
    -- WICHTIG: Prüfe ob Cursor überhaupt aktiviert ist!
    if not AiB_CursorConfig.enabled then
        AiB_Cursor_CursorFrame:Hide()
        return
    end

    -- Check Modifiers first (Override - Always Show)
    local shiftDown = IsShiftKeyDown()
    local ctrlDown = IsControlKeyDown()
    local altDown = IsAltKeyDown()
    
    local modifierShow = (shiftDown and AiB_CursorConfig.shiftAction == "Show Rings") or
                         (ctrlDown and AiB_CursorConfig.ctrlAction == "Show Rings") or
                         (altDown and AiB_CursorConfig.altAction == "Show Rings")

    if modifierShow then
        AiB_Cursor_CursorFrame:Show()
        return
    end

    -- Check Combat State
    local inCombat = forceState
    if inCombat == nil then
        inCombat = UnitAffectingCombat("player")  -- FIXED: Richtige Combat-Detection!
    end

    -- Determine Base Visibility
    if AiB_CursorConfig.showOnlyInCombat then
        if inCombat then
            AiB_Cursor_CursorFrame:Show()
        else
            AiB_Cursor_CursorFrame:Hide()
        end
    else
        -- Show Only In Combat is FALSE (Normally Always Visible)
        -- BUT, if any key is configured to "Show Rings", we want to hide it by default
        -- so that the key press actually does something (Push-to-Show).
        
        local isAnyShowRingsConfigured = (AiB_CursorConfig.shiftAction == "Show Rings") or
                                         (AiB_CursorConfig.ctrlAction == "Show Rings") or
                                         (AiB_CursorConfig.altAction == "Show Rings")
                                         
        if isAnyShowRingsConfigured then
            AiB_Cursor_CursorFrame:Hide()
        else
            AiB_Cursor_CursorFrame:Show()
        end
    end
end

function Cursor:ResetCooldownFrames()
    -- Stop any running animations
    Cursor.isGCDAnimating = false
    Cursor.isCasting = false
    Cursor.gcdCompletionTime = nil
    Cursor.castCompletionTime = nil
    
    -- Destroy old GCD frames
    if Cursor.GCDCooldownFrame then
        Cursor.GCDCooldownFrame:Hide()
        Cursor.GCDCooldownFrame:SetParent(nil)
        Cursor.GCDCooldownFrame = nil
    end
    if Cursor.GCDBackgroundFrame then
        Cursor.GCDBackgroundFrame:Hide()
        Cursor.GCDBackgroundFrame:SetParent(nil)
        Cursor.GCDBackgroundFrame = nil
    end
    
    -- Destroy old Cast frames
    if Cursor.CastFrame then
        Cursor.CastFrame:Hide()
        Cursor.CastFrame:SetParent(nil)
        Cursor.CastFrame = nil
    end
    if Cursor.CastBackgroundFrame then
        Cursor.CastBackgroundFrame:Hide()
        Cursor.CastBackgroundFrame:SetParent(nil)
        Cursor.CastBackgroundFrame = nil
    end
    
    local timestamp = GetTime()
    
    -- Recreate GCD Background Frame
    local gcdBgFrame = CreateFrame("Cooldown", nil, AiB_Cursor_CursorFrame)
    gcdBgFrame:SetSize(70, 70)
    gcdBgFrame:SetPoint("CENTER", AiB_Cursor_CursorFrame, "CENTER")
    gcdBgFrame:SetFrameLevel(2)
    Cursor.GCDBackgroundFrame = gcdBgFrame
    gcdBgFrame:SetSwipeTexture("Interface\\AddOns\\aib\\textures\\cursor\\Ring_Main")
    gcdBgFrame:SetSwipeColor(0.5, 0.5, 0.5, 0.7)
    gcdBgFrame:SetReverse(false)
    gcdBgFrame:SetHideCountdownNumbers(true)
    -- Set a cooldown that already finished to show as a static full circle
    gcdBgFrame:SetCooldown(GetTime() - 1, 0.01)
    gcdBgFrame:Hide()

    -- Recreate GCD Cooldown Frame
    local cooldownFrame = CreateFrame("Cooldown", nil, AiB_Cursor_CursorFrame)
    cooldownFrame:SetSize(50, 50)
    cooldownFrame:SetPoint("CENTER", AiB_Cursor_CursorFrame, "CENTER")
    cooldownFrame:SetFrameLevel(3)
    Cursor.GCDCooldownFrame = cooldownFrame
    cooldownFrame:SetSwipeTexture("Interface\\AddOns\\aib\\textures\\cursor\\Ring_Main")
    local r, g, b = Cursor:GetClassColor("gcd")
    cooldownFrame:SetSwipeColor(r, g, b, 1.0) 
    cooldownFrame:SetHideCountdownNumbers(true)
    
    -- Apply rotation from clock position and direction
    local gcdRotation = AiB_CursorConfig.gcdRotation or 12
    local gcdDirection = AiB_CursorConfig.gcdDirection or "clockwise"
    local gcdFillDrain = AiB_CursorConfig.gcdFillDrain or "drain"
    cooldownFrame:SetRotation(Cursor:ClockToRadians(gcdRotation))
    
    cooldownFrame:Hide()

    -- Recreate Cast Background Frame
    local castBgFrame = CreateFrame("Cooldown", nil, AiB_Cursor_CursorFrame)
    castBgFrame:SetSize(70, 70)
    castBgFrame:SetPoint("CENTER", AiB_Cursor_CursorFrame, "CENTER")
    castBgFrame:SetFrameLevel(2)
    Cursor.CastBackgroundFrame = castBgFrame
    castBgFrame:SetSwipeTexture("Interface\\AddOns\\aib\\textures\\cursor\\Ring_Main")
    castBgFrame:SetSwipeColor(0.5, 0.5, 0.5, 0.7)
    castBgFrame:SetReverse(false)
    castBgFrame:SetHideCountdownNumbers(true)
    -- Set a cooldown that already finished to show as a static full circle
    castBgFrame:SetCooldown(GetTime() - 1, 0.01)
    castBgFrame:Hide()

    -- Recreate Cast Frame
    local castFrame = CreateFrame("Cooldown", nil, AiB_Cursor_CursorFrame)
    castFrame:SetSize(90, 90) 
    castFrame:SetPoint("CENTER", AiB_Cursor_CursorFrame, "CENTER")
    castFrame:SetFrameLevel(3)
    Cursor.CastFrame = castFrame
    castFrame:SetSwipeTexture("Interface\\AddOns\\aib\\textures\\cursor\\Ring_Main")
    r, g, b = Cursor:GetClassColor("cast")
    castFrame:SetSwipeColor(r, g, b, 1.0) 
    castFrame:SetHideCountdownNumbers(true)
    
    -- Apply rotation from clock position and direction
    local castRotation = AiB_CursorConfig.castRotation or 12
    local castDirection = AiB_CursorConfig.castDirection or "clockwise"
    local castFillDrain = AiB_CursorConfig.castFillDrain or "drain"
    castFrame:SetRotation(Cursor:ClockToRadians(castRotation))
    
    castFrame:Hide()
    
    -- Reapply settings to ensure correct ring sizes (e.g., Main Ring + Cast)
    if AiB_Cursor.ApplySettings then
        AiB_Cursor:ApplySettings()
    end
end

function Cursor:SetupUI()
    -- SetupUI() starting

    local transparency = AiB_CursorConfig.transparency or 1.0
    AiB_Cursor_CursorFrame:SetAlpha(transparency)
    AiB_Cursor_CursorFrame:SetFrameStrata("HIGH")
    AiB_Cursor_CursorFrame:SetToplevel(false)
    AiB_Cursor_CursorFrame:Show()
    Cursor:SetGroupScale(Cursor.currentGroupScale)
    AiB_Cursor_CursorFrame.MainRing:Show()
    
    Cursor:UpdateReticle()

    local gcdBgFrame = CreateFrame("Cooldown", "AiB_Cursor_GCD_BG_COOLDOWN", AiB_Cursor_CursorFrame)
    gcdBgFrame:SetSize(70, 70)
    gcdBgFrame:SetPoint("CENTER", AiB_Cursor_CursorFrame, "CENTER")
    gcdBgFrame:SetFrameLevel(2)
    Cursor.GCDBackgroundFrame = gcdBgFrame
    gcdBgFrame:SetSwipeTexture("Interface\\AddOns\\aib\\textures\\cursor\\Ring_Main")
    gcdBgFrame:SetSwipeColor(0.5, 0.5, 0.5, 0.7)
    gcdBgFrame:SetReverse(false)
    gcdBgFrame:SetHideCountdownNumbers(true)
    -- Set a cooldown that already finished to show as a static full circle
    gcdBgFrame:SetCooldown(GetTime() - 1, 0.01)
    gcdBgFrame:Hide()

    local cooldownFrame = CreateFrame("Cooldown", "AiB_Cursor_GCD_COOLDOWN", AiB_Cursor_CursorFrame)
    cooldownFrame:SetSize(50, 50)
    cooldownFrame:SetPoint("CENTER", AiB_Cursor_CursorFrame, "CENTER")
    cooldownFrame:SetFrameLevel(3)
    Cursor.GCDCooldownFrame = cooldownFrame
    cooldownFrame:SetSwipeTexture("Interface\\AddOns\\aib\\textures\\cursor\\Ring_Main")
    local r, g, b = Cursor:GetClassColor("gcd")
    cooldownFrame:SetSwipeColor(r, g, b, 1.0) 
    cooldownFrame:SetHideCountdownNumbers(true)
    
    -- Apply rotation from clock position and direction
    local gcdRotation = AiB_CursorConfig.gcdRotation or 12
    local gcdDirection = AiB_CursorConfig.gcdDirection or "clockwise"
    local gcdFillDrain = AiB_CursorConfig.gcdFillDrain or "drain"
    cooldownFrame:SetRotation(Cursor:ClockToRadians(gcdRotation))
    
    --     cooldownFrame:Hide()

    local castBgFrame = CreateFrame("Cooldown", "AiB_Cursor_CAST_BG_COOLDOWN", AiB_Cursor_CursorFrame)
    castBgFrame:SetSize(70, 70)
    castBgFrame:SetPoint("CENTER", AiB_Cursor_CursorFrame, "CENTER")
    castBgFrame:SetFrameLevel(2)
    Cursor.CastBackgroundFrame = castBgFrame
    castBgFrame:SetSwipeTexture("Interface\\AddOns\\aib\\textures\\cursor\\Ring_Main")
    castBgFrame:SetSwipeColor(0.5, 0.5, 0.5, 0.7)
    castBgFrame:SetReverse(false)
    castBgFrame:SetHideCountdownNumbers(true)
    -- Set a cooldown that already finished to show as a static full circle
    castBgFrame:SetCooldown(GetTime() - 1, 0.01)
    castBgFrame:Hide()

    local castFrame = CreateFrame("Cooldown", "AiB_Cursor_CAST_COOLDOWN", AiB_Cursor_CursorFrame)
    castFrame:SetSize(90, 90) 
    castFrame:SetPoint("CENTER", AiB_Cursor_CursorFrame, "CENTER")
    castFrame:SetFrameLevel(3)
    Cursor.CastFrame = castFrame
    castFrame:SetSwipeTexture("Interface\\AddOns\\aib\\textures\\cursor\\Ring_Main")
    r, g, b = Cursor:GetClassColor("cast")
    castFrame:SetSwipeColor(r, g, b, 1.0) 
    castFrame:SetHideCountdownNumbers(true)
    
    -- Apply rotation from clock position and direction
    local castRotation = AiB_CursorConfig.castRotation or 12
    local castDirection = AiB_CursorConfig.castDirection or "clockwise"
    local castFillDrain = AiB_CursorConfig.castFillDrain or "drain"
    castFrame:SetRotation(Cursor:ClockToRadians(castRotation))
    
    --     castFrame:Hide()

    -- Health Background - use Texture instead of Cooldown since it's always full
    -- DISABLED:     local healthBgFrame = AiB_Cursor_CursorFrame:CreateTexture(nil, "ARTWORK")
    -- DISABLED:     healthBgFrame:SetSize(70, 70)
    -- DISABLED:     healthBgFrame:SetPoint("CENTER", AiB_Cursor_CursorFrame, "CENTER")
    -- DISABLED:     healthBgFrame:SetTexture("Interface\\AddOns\\aib\\textures\\cursor\\Ring_Main")
    -- DISABLED:     healthBgFrame:SetVertexColor(0.5, 0.5, 0.5, 0.7)
    -- DISABLED:     Cursor.HealthBackgroundFrame = healthBgFrame
    -- DISABLED:     healthBgFrame:Hide()

    -- DISABLED:     local healthFrame = CreateFrame("Cooldown", "AiB_Cursor_HEALTH_COOLDOWN", AiB_Cursor_CursorFrame)
    -- DISABLED:     healthFrame:SetSize(70, 70)
    -- DISABLED:     healthFrame:SetPoint("CENTER", AiB_Cursor_CursorFrame, "CENTER")
    -- DISABLED:     healthFrame:SetFrameLevel(3)
    -- DISABLED:     Cursor.HealthFrame = healthFrame
    -- DISABLED:     healthFrame:SetSwipeTexture("Interface\\AddOns\\aib\\textures\\cursor\\Ring_Main")
    -- DISABLED:     healthFrame:SetSwipeColor(1.0, 0.0, 0.0, 0.8)
    -- DISABLED:     healthFrame:SetReverse(false)
    -- DISABLED:     healthFrame:SetHideCountdownNumbers(true)
    -- DISABLED:     healthFrame:Hide()

    -- DISABLED:     local powerFrame = CreateFrame("Cooldown", "AiB_Cursor_POWER_COOLDOWN", AiB_Cursor_CursorFrame)
    -- DISABLED:     powerFrame:SetSize(80, 80)
    -- DISABLED:     powerFrame:SetPoint("CENTER", AiB_Cursor_CursorFrame, "CENTER")
    -- DISABLED:     powerFrame:SetFrameLevel(1)
    -- DISABLED:     Cursor.PowerFrame = powerFrame
    -- DISABLED:     powerFrame:SetSwipeTexture("Interface\\AddOns\\aib\\textures\\cursor\\Ring_Main")
    -- DISABLED:     powerFrame:SetSwipeColor(0.0, 0.5, 1.0, 0.8)
    -- DISABLED:     powerFrame:SetReverse(false)
    -- DISABLED:     powerFrame:SetHideCountdownNumbers(true)
    -- DISABLED:     powerFrame:SetHideCountdownNumbers(true)
    -- DISABLED:     powerFrame:Hide()
    -- DISABLED: 
    local pingFrame = AiB_Cursor_CursorFrame:CreateTexture(nil, "OVERLAY")
    pingFrame:SetTexture("Interface\\AddOns\\aib\\textures\\cursor\\Ring_Main")
    pingFrame:SetBlendMode("ADD")
    pingFrame:SetVertexColor(1.0, 1.0, 1.0, 0.5)
    pingFrame:Hide()
    Cursor.PingFrame = pingFrame

    -- Crosshair Frame
    local crosshairFrame = CreateFrame("Frame", "AiB_Cursor_CrosshairFrame", UIParent)
    crosshairFrame:SetFrameStrata("BACKGROUND")
    crosshairFrame:SetAllPoints()
    crosshairFrame:EnableMouse(false)
    crosshairFrame:Hide()
    Cursor.CrosshairFrame = crosshairFrame

    local function CreateLine(name)
        local line = crosshairFrame:CreateTexture(nil, "OVERLAY")
        line:SetColorTexture(1, 1, 1, 0.5) -- Red, semi-transparent
        line:SetWidth(2) -- Thickness
        return line
    end

    crosshairFrame.Top = CreateLine("Top")
    crosshairFrame.Bottom = CreateLine("Bottom")
    crosshairFrame.Left = CreateLine("Left")
    crosshairFrame.Right = CreateLine("Right")
    
    -- Adjust line thickness for horizontal lines (height instead of width)
    crosshairFrame.Left:SetWidth(0) -- Reset width
    crosshairFrame.Left:SetHeight(2)
    crosshairFrame.Right:SetWidth(0)
    crosshairFrame.Right:SetHeight(2)



    -- DISABLED:     Cursor:UpdateHealthRing()
    -- DISABLED:     Cursor:UpdatePowerRing()

    Cursor:InitializeTrail()
    Cursor:InitializeSeasonalParticles()


    -- Call ApplySettings with error handling
    local success, err = pcall(function()
        AiB_Cursor:ApplySettings()
    end)
    
    if not success then
    else
    end
    
    -- FORCE ENABLE GCD and Cast - set flags to true!
    AiB_Cursor.enableGCD = true
    AiB_Cursor.enableCast = true
    
    -- REMOVED:     -- FORCE SHOW GCD and Cast rings - they should be visible!
    -- REMOVED:     if Cursor.GCDCooldownFrame then
    -- REMOVED:         Cursor.GCDCooldownFrame:Show()
    -- REMOVED:     end
    -- REMOVED:     if Cursor.CastFrame then
    -- REMOVED:         Cursor.CastFrame:Show()
    -- REMOVED:     end
    TrackerFrame:UnregisterEvent("PLAYER_ENTERING_WORLD")
end

function Cursor:OnInitialize()
    Cursor.TrackerFrame = TrackerFrame

    TrackerFrame:RegisterEvent("PLAYER_ENTERING_WORLD")
    TrackerFrame:RegisterEvent("PLAYER_REGEN_DISABLED")
    TrackerFrame:RegisterEvent("PLAYER_REGEN_ENABLED")
    
    -- GCD und Cast Events
    TrackerFrame:RegisterEvent("UNIT_SPELLCAST_START")
    TrackerFrame:RegisterEvent("UNIT_SPELLCAST_STOP")
    TrackerFrame:RegisterEvent("UNIT_SPELLCAST_FAILED")
    TrackerFrame:RegisterEvent("UNIT_SPELLCAST_INTERRUPTED")
    TrackerFrame:RegisterEvent("UNIT_SPELLCAST_SUCCEEDED")
    TrackerFrame:RegisterEvent("UNIT_SPELLCAST_CHANNEL_START")
    TrackerFrame:RegisterEvent("UNIT_SPELLCAST_CHANNEL_STOP")
    TrackerFrame:RegisterEvent("UNIT_SPELLCAST_CHANNEL_UPDATE")
    
    -- DISABLED:     -- Health und Power Events
    -- DISABLED:     TrackerFrame:RegisterEvent("UNIT_HEALTH")
    -- DISABLED:     TrackerFrame:RegisterEvent("UNIT_MAXHEALTH")
    -- DISABLED:     TrackerFrame:RegisterEvent("UNIT_POWER_UPDATE")
    -- DISABLED:     TrackerFrame:RegisterEvent("UNIT_MAXPOWER")


    TrackerFrame:SetScript("OnEvent", function(self, event, ...)
        if event == "PLAYER_ENTERING_WORLD" then
            if AiB_Cursor_CursorFrame then
                Cursor:SetupUI()
            end

        elseif event:match("UNIT_SPELLCAST_") then 
            Cursor:GCDCastHandler(self, event, ...)
            Cursor:CastEventHandler(self, event, ...) 

        -- DISABLED:         elseif event == "UNIT_HEALTH" or event == "UNIT_MAXHEALTH" then
        -- DISABLED:             Cursor:HealthEventHandler(self, event, ...)
        -- DISABLED: 
        -- DISABLED:         elseif event == "UNIT_POWER_UPDATE" or event == "UNIT_MAXPOWER" then
        -- DISABLED:             Cursor:PowerEventHandler(self, event, ...)

        elseif event == "PLAYER_REGEN_DISABLED" then
            Cursor:UpdateVisibility(true)
        elseif event == "PLAYER_REGEN_ENABLED" then
            Cursor:UpdateVisibility(false)
        end
    end)

    TrackerFrame:SetScript("OnUpdate", function(self, elapsed) Cursor:OnUpdate(elapsed) end)
    TrackerFrame:Show()
    Cursor:OnUpdate(0)
    
    -- WICHTIG: SetupUI direkt aufrufen, da PLAYER_ENTERING_WORLD schon vorbei ist
    if AiB_Cursor_CursorFrame then
        Cursor:SetupUI()
    else
    end
end
LoaderFrame:SetScript("OnEvent", function(self, event, addon)
    -- v2.1.0.0: PLAYER_LOGIN statt ADDON_LOADED, damit AceDB (aib.lua) bereits
    -- gelaufen ist und AiB_CursorConfig gesetzt wurde.
    if event == "PLAYER_LOGIN" then
        if not AiB_CursorConfig then
            C_Timer.After(1, function() Cursor:OnInitialize() end)
            self:UnregisterAllEvents()
            return
        end
        Cursor:OnInitialize()
        self:UnregisterAllEvents()
    end
end)
LoaderFrame:RegisterEvent("PLAYER_LOGIN")
