-- ============================================================================
-- File: ArenaCore/Core/PartyClassIndicators.lua (v2.0)
-- Purpose: Party class indicators
-- Rewritten Nov 1, 2025
-- ============================================================================

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

-- Class icon paths (ArenaCore Custom theme)
local CLASS_ICON_PATHS = {
    DEATHKNIGHT = "Interface\\AddOns\\ArenaCore\\Media\\Classicons\\Deathknight",
    DEMONHUNTER = "Interface\\AddOns\\ArenaCore\\Media\\Classicons\\Demonhunter",
    DRUID = "Interface\\AddOns\\ArenaCore\\Media\\Classicons\\Druid",
    EVOKER = "Interface\\AddOns\\ArenaCore\\Media\\Classicons\\Evoker",
    HUNTER = "Interface\\AddOns\\ArenaCore\\Media\\Classicons\\Hunter",
    MAGE = "Interface\\AddOns\\ArenaCore\\Media\\Classicons\\Mage",
    MONK = "Interface\\AddOns\\ArenaCore\\Media\\Classicons\\Monk",
    PALADIN = "Interface\\AddOns\\ArenaCore\\Media\\Classicons\\Paladin",
    PRIEST = "Interface\\AddOns\\ArenaCore\\Media\\Classicons\\Priest",
    ROGUE = "Interface\\AddOns\\ArenaCore\\Media\\Classicons\\Rogue",
    SHAMAN = "Interface\\AddOns\\ArenaCore\\Media\\Classicons\\Shaman",
    WARLOCK = "Interface\\AddOns\\ArenaCore\\Media\\Classicons\\Warlock",
    WARRIOR = "Interface\\AddOns\\ArenaCore\\Media\\Classicons\\Warrior",
}

-- ColdClasses theme paths (WoW Default Style+Midnight Chill)
-- CRITICAL: Must include .png extension for PNG files
local COLDCLASSES_ICON_PATHS = {
    DEATHKNIGHT = "Interface\\AddOns\\ArenaCore\\Media\\Classicons\\ColdClasses\\deathknight.png",
    DEMONHUNTER = "Interface\\AddOns\\ArenaCore\\Media\\Classicons\\ColdClasses\\demonhunter.png",
    DRUID = "Interface\\AddOns\\ArenaCore\\Media\\Classicons\\ColdClasses\\druid.png",
    EVOKER = "Interface\\AddOns\\ArenaCore\\Media\\Classicons\\ColdClasses\\evoker.png",
    HUNTER = "Interface\\AddOns\\ArenaCore\\Media\\Classicons\\ColdClasses\\hunter.png",
    MAGE = "Interface\\AddOns\\ArenaCore\\Media\\Classicons\\ColdClasses\\mage.png",
    MONK = "Interface\\AddOns\\ArenaCore\\Media\\Classicons\\ColdClasses\\monk.png",
    PALADIN = "Interface\\AddOns\\ArenaCore\\Media\\Classicons\\ColdClasses\\paladin.png",
    PRIEST = "Interface\\AddOns\\ArenaCore\\Media\\Classicons\\ColdClasses\\priest.png",
    ROGUE = "Interface\\AddOns\\ArenaCore\\Media\\Classicons\\ColdClasses\\rogue.png",
    SHAMAN = "Interface\\AddOns\\ArenaCore\\Media\\Classicons\\ColdClasses\\shaman.png",
    WARLOCK = "Interface\\AddOns\\ArenaCore\\Media\\Classicons\\ColdClasses\\warlock.png",
    WARRIOR = "Interface\\AddOns\\ArenaCore\\Media\\Classicons\\ColdClasses\\warrior.png",
}

-- Get class icon path based on useCustomIcons setting
local function GetClassIconPath(classToken)
    if not classToken then return nil end
    
    -- Get settings from database
    local db = AC.DB and AC.DB.profile
    local useCustomIcons = db and db.moreGoodies and db.moreGoodies.partyClassSpecs and db.moreGoodies.partyClassSpecs.useCustomIcons
    
    -- When checkbox is ON: Use ArenaCore custom icons
    -- When checkbox is OFF: Use Midnight Chill (coldclasses) icons
    if useCustomIcons then
        -- Use ArenaCore Custom icons
        return CLASS_ICON_PATHS[classToken]
    else
        -- Use Midnight Chill (coldclasses) icons
        return COLDCLASSES_ICON_PATHS[classToken]
    end
end

-- ============================================================================
-- INDEPENDENT FRAME STORAGE (for custom nameplate addon compatibility)
-- ============================================================================
-- Store frames independently so they work with Platynator/Plater
-- These addons reparent Blizzard frames to hidden frames, so we need our own
local independentFrames = {}

-- OnUpdate handler to continuously position frames above nameplates
local function UpdateFramePosition(self, elapsed)
    if not self.unit then return end
    
    local nameplate = C_NamePlate.GetNamePlateForUnit(self.unit)
    if nameplate and nameplate:IsShown() then
        self:ClearAllPoints()
        self:SetPoint("BOTTOM", nameplate, "TOP", self.offsetX or 0, self.offsetY or 0)
        self:Show()
    else
        self:Hide()
    end
end

-- ============================================================================
-- BBP PATTERN: Single function called from NAME_PLATE_UNIT_ADDED
-- ============================================================================

function AC.UpdatePartyClassIndicator(frame)
    if not frame or not frame.unit then return end
    
    -- Don't check IsForbidden/IsProtected - we're using a dummy table now, not a real frame
    
    -- Get ArenaCore config
    local db = AC.DB and AC.DB.profile and AC.DB.profile.moreGoodies and AC.DB.profile.moreGoodies.partyClassSpecs
    if not db or not db.mode or db.mode == "off" then
        -- Feature disabled - restore any hidden elements
        if frame.__acClassIndicatorActive then
            if frame.HealthBarsContainer then
                frame.HealthBarsContainer:SetAlpha(1)
            end
            if frame.name then
                frame.name:SetAlpha(1)
            end
            frame.__acClassIndicatorActive = nil
        end
        if frame.ArenaCore_ClassIndicator then
            frame.ArenaCore_ClassIndicator:Hide()
        end
        if frame.ArenaCore_Pointer then
            frame.ArenaCore_Pointer:Hide()
        end
        -- Restore raid target markers when feature is off
        if frame.RaidTargetFrame and frame.RaidTargetFrame.RaidTargetIcon then
            frame.RaidTargetFrame.RaidTargetIcon:SetAlpha(1)
        end
        return
    end
    
    -- Get unit info first
    local unitForData = frame.displayedUnit or frame.unit
    if not unitForData or not UnitExists(unitForData) then return end
    
    -- Only handle nameplates
    -- CRITICAL: For custom nameplate addons, frame.unit may not contain "nameplate"
    -- Check if the unit itself is a nameplate unit
    if not unitForData:find("nameplate") then return end
    
    -- CRITICAL: Only work on FRIENDLY PLAYERS, not NPCs (BBP pattern)
    if not UnitIsPlayer(unitForData) or not UnitIsFriend("player", unitForData) then
        -- NPC or enemy - don't touch anything
        if frame.__acClassIndicatorActive then
            if frame.HealthBarsContainer then
                frame.HealthBarsContainer:SetAlpha(1)
            end
            frame.__acClassIndicatorActive = nil
        end
        if frame.ArenaCore_ClassIndicator then
            frame.ArenaCore_ClassIndicator:Hide()
        end
        if frame.ArenaCore_Pointer then
            frame.ArenaCore_Pointer:Hide()
        end
        -- Restore raid target markers for NPCs/enemies
        if frame.RaidTargetFrame and frame.RaidTargetFrame.RaidTargetIcon then
            frame.RaidTargetFrame.RaidTargetIcon:SetAlpha(1)
        end
        return
    end
    
    -- Check mode setting (party vs all)
    local showOnThisUnit = false
    if db.mode == "all" then
        showOnThisUnit = true
    elseif db.mode == "party" then
        showOnThisUnit = UnitInParty(unitForData)
    end
    
    -- If mode doesn't match, hide and return
    if not showOnThisUnit then
        -- Mode doesn't match - hide everything
        if frame.__acClassIndicatorActive then
            if frame.HealthBarsContainer then
                frame.HealthBarsContainer:SetAlpha(1)
            end
            frame.__acClassIndicatorActive = nil
        end
        if frame.ArenaCore_ClassIndicator then
            frame.ArenaCore_ClassIndicator:Hide()
        end
        if frame.ArenaCore_Pointer then
            frame.ArenaCore_Pointer:Hide()
        end
        -- Restore raid target markers for enemies/neutrals
        if frame.RaidTargetFrame and frame.RaidTargetFrame.RaidTargetIcon then
            frame.RaidTargetFrame.RaidTargetIcon:SetAlpha(1)
        end
        return
    end
    
    -- Don't show on self
    if UnitIsUnit(unitForData, "player") then
        if frame.ArenaCore_ClassIndicator then
            frame.ArenaCore_ClassIndicator:Hide()
        end
        if frame.ArenaCore_Pointer then
            frame.ArenaCore_Pointer:Hide()
        end
        -- Restore raid target markers for self
        if frame.RaidTargetFrame and frame.RaidTargetFrame.RaidTargetIcon then
            frame.RaidTargetFrame.RaidTargetIcon:SetAlpha(1)
        end
        return
    end
    
    -- Get class info
    local _, class = UnitClass(unitForData)
    if not class then return end
    
    -- ========================================================================
    -- CLASS INDICATOR (Icon above nameplate)
    -- ========================================================================
    
    -- Always show class icons when feature is enabled (mode != "off")
    if true then
        -- Get or create independent frame (not a child of nameplate)
        local classFrame = independentFrames[unitForData]
        if not classFrame then
            -- Create frame attached to UIParent (independent of nameplate)
            classFrame = CreateFrame("Frame", "ArenaCore_ClassIndicator_" .. unitForData, UIParent)
            classFrame:SetSize(32, 32)
            classFrame:SetFrameStrata("HIGH")
            classFrame:SetFrameLevel(1000)
            independentFrames[unitForData] = classFrame
            
            -- Store unit for OnUpdate positioning
            classFrame.unit = unitForData
            
            -- Set up continuous positioning
            classFrame:SetScript("OnUpdate", UpdateFramePosition)
            
            -- Store reference on frame for compatibility
            frame.ArenaCore_ClassIndicator = classFrame
            
            -- Create the class icon texture
            classFrame.icon = classFrame:CreateTexture(nil, "ARTWORK")
            classFrame.icon:SetPoint("CENTER", classFrame)
            classFrame.icon:SetSize(28, 28)
            
            -- Create circular mask
            classFrame.mask = classFrame:CreateMaskTexture()
            classFrame.mask:SetTexture("Interface\\CharacterFrame\\TempPortraitAlphaMask", "CLAMPTOBLACKADDITIVE", "CLAMPTOBLACKADDITIVE")
            classFrame.mask:SetSize(28, 28)
            classFrame.mask:SetPoint("CENTER", classFrame.icon)
            classFrame.icon:AddMaskTexture(classFrame.mask)
            
            -- Create border using BlackOutline.tga
            classFrame.border = classFrame:CreateTexture(nil, "OVERLAY")
            classFrame.border:SetAllPoints(classFrame)
            classFrame.border:SetTexture("Interface\\AddOns\\ArenaCore\\Media\\Classicons\\BlackOutline.tga")
        end
        
        -- Position frame above nameplate using world coordinates
        local nameplateFrame = C_NamePlate.GetNamePlateForUnit(unitForData)
        if nameplateFrame then
            classFrame:SetPoint("BOTTOM", nameplateFrame, "TOP", 0, 8)
        end
        
        -- Apply scale from settings
        local finalScale
        do
            local pm = AC.ProfileManager
            local scalePixels = pm and pm.GetSetting and pm:GetSetting("moreGoodies.partyClassSpecs.scale")
            if type(scalePixels) == "number" then
                local currentScale = AC.ConvertPixelsToScale and AC:ConvertPixelsToScale(scalePixels, 50, 360, 1, 12) or 6.5
                finalScale = 0.5 + (currentScale - 1) * (2.5 / 11)
            else
                local rawScale = (db.scale) or 100
                if rawScale <= 12 then
                    finalScale = 0.5 + (rawScale - 1) * (2.5 / 11)
                else
                    finalScale = rawScale / 100
                end
            end
            finalScale = math.max(0.5, math.min(finalScale or 1.0, 3.0))
            classFrame:SetScale(finalScale)
        end
        
        -- Apply horizontal/vertical offsets
        local offX, offY = 0, 0
        do
            local pm = AC.ProfileManager
            local px = pm and pm.GetSetting and pm:GetSetting("moreGoodies.partyClassSpecs.offsetX")
            local py = pm and pm.GetSetting and pm:GetSetting("moreGoodies.partyClassSpecs.offsetY")
            if type(px) ~= "number" then
                px = db.offsetX or 0
            end
            if type(py) ~= "number" then
                py = db.offsetY or 0
            end
            offX, offY = tonumber(px) or 0, tonumber(py) or 0
        end
        
        local baseY = 8
        -- Store offsets for OnUpdate handler
        classFrame.offsetX = offX
        classFrame.offsetY = baseY + offY
        
        -- Set class icon texture (use custom ArenaCore icons)
        -- CRITICAL FIX: Check if this is a healer and showHealerIcon is enabled
        local useHealerIcon = false
        if db.showHealerIcon then
            -- Check if this unit is a healer using role assignment
            local role = UnitGroupRolesAssigned(unitForData)
            if role == "HEALER" then
                useHealerIcon = true
            end
        end
        
        if useHealerIcon then
            -- Use custom ArenaCore healer icon
            classFrame.icon:SetTexture("Interface\\AddOns\\ArenaCore\\Media\\Classicons\\HealerPointer.tga")
            classFrame.icon:SetTexCoord(0, 1, 0, 1) -- Full texture for healer icon
        else
            -- Use normal class icon (respects theme setting)
            local iconPath = GetClassIconPath(class)
            if iconPath then
                classFrame.icon:SetTexture(iconPath)
                classFrame.icon:SetTexCoord(0.05, 0.95, 0.05, 0.95)
            end
        end
        
        -- Hide raid target markers (skull, cross, moon, etc.) when showing class icons
        if frame.RaidTargetFrame and frame.RaidTargetFrame.RaidTargetIcon then
            frame.RaidTargetFrame.RaidTargetIcon:SetAlpha(0)
        end
        
        classFrame:Show()
    else
        local classFrame = independentFrames[unitForData]
        if classFrame then
            classFrame:Hide()
        end
    end
    
    -- ========================================================================
    -- PARTY POINTER (Arrow above nameplate)
    -- ========================================================================
    
    -- Update pointer (triangle arrow) with separate positioning
    if db.showPointers then
        -- Get or create independent pointer frame
        local pointerFrame = independentFrames[unitForData .. "_pointer"]
        if not pointerFrame then
            -- Create frame attached to UIParent (independent of nameplate)
            pointerFrame = CreateFrame("Frame", "ArenaCore_Pointer_" .. unitForData, UIParent)
            pointerFrame:SetSize(34, 48)
            pointerFrame:SetFrameStrata("HIGH")
            pointerFrame:SetFrameLevel(1001)
            independentFrames[unitForData .. "_pointer"] = pointerFrame
            
            -- Store unit for OnUpdate positioning
            pointerFrame.unit = unitForData
            
            -- Set up continuous positioning
            pointerFrame:SetScript("OnUpdate", UpdateFramePosition)
            
            -- Store reference on frame for compatibility
            frame.ArenaCore_Pointer = pointerFrame
            
            pointerFrame.icon = pointerFrame:CreateTexture(nil, "ARTWORK")
            pointerFrame.icon:SetAtlas("UI-QuestPoiImportant-QuestNumber-SuperTracked")
            pointerFrame.icon:SetSize(34, 48)
            pointerFrame.icon:SetPoint("BOTTOM", pointerFrame, "BOTTOM", 0, 5)
            pointerFrame.icon:SetDesaturated(true)
            pointerFrame.icon:SetTexelSnappingBias(0.0)
            pointerFrame.icon:SetSnapToPixelGrid(false)
        end
        
        -- Apply pointer scale
        local pointerScale
        do
            local pm = AC.ProfileManager
            local scalePixels = pm and pm.GetSetting and pm:GetSetting("moreGoodies.partyClassSpecs.pointerScale")
            if type(scalePixels) == "number" then
                local currentScale = AC.ConvertPixelsToScale and AC:ConvertPixelsToScale(scalePixels, 50, 360, 1, 12) or 6.5
                pointerScale = 0.5 + (currentScale - 1) * (2.5 / 11)
            else
                local rawScale = db.pointerScale or 100
                if rawScale <= 12 then
                    pointerScale = 0.5 + (rawScale - 1) * (2.5 / 11)
                else
                    pointerScale = rawScale / 100
                end
            end
            pointerScale = math.max(0.5, math.min(pointerScale or 1.0, 3.0))
            pointerFrame:SetScale(pointerScale)
        end
        
        -- Apply pointer offsets
        local ptrOffX, ptrOffY = 0, 0
        do
            local pm = AC.ProfileManager
            local px = pm and pm.GetSetting and pm:GetSetting("moreGoodies.partyClassSpecs.pointerOffsetX")
            local py = pm and pm.GetSetting and pm:GetSetting("moreGoodies.partyClassSpecs.pointerOffsetY")
            if type(px) ~= "number" then
                px = db.pointerOffsetX or 0
            end
            if type(py) ~= "number" then
                py = db.pointerOffsetY or 0
            end
            ptrOffX, ptrOffY = tonumber(px) or 0, tonumber(py) or 0
        end
        
        -- Position pointer above class icon
        local basePointerY = 40
        -- Store offsets for OnUpdate handler
        pointerFrame.offsetX = ptrOffX
        pointerFrame.offsetY = basePointerY + ptrOffY
        
        -- Color pointer based on class
        if class and RAID_CLASS_COLORS[class] then
            local classColor = RAID_CLASS_COLORS[class]
            pointerFrame.icon:SetVertexColor(classColor.r, classColor.g, classColor.b, 1)
        end
        
        pointerFrame:Show()
    else
        local pointerFrame = independentFrames[unitForData .. "_pointer"]
        if pointerFrame then
            pointerFrame:Hide()
        end
    end
    
    -- ========================================================================
    -- HIDE HEALTH BARS (BBP Pattern with flags)
    -- ========================================================================
    
    if db.hideHealthBars then
        -- BBP PATTERN: Use flag to track state
        if not frame.__acClassIndicatorActive then
            if frame.HealthBarsContainer then
                frame.HealthBarsContainer:SetAlpha(0)
            end
            if frame.selectionHighlight then
                frame.selectionHighlight:SetAlpha(0)
            end
            frame.__acClassIndicatorActive = true  -- Set flag
        end
    else
        -- Restore if previously hidden
        if frame.__acClassIndicatorActive then
            if frame.HealthBarsContainer then
                frame.HealthBarsContainer:SetAlpha(1)
            end
            if frame.selectionHighlight then
                frame.selectionHighlight:SetAlpha(0.22)
            end
            frame.__acClassIndicatorActive = nil  -- Clear flag
        end
    end
    
    -- ========================================================================
    -- HIDE NAMES (BBP Pattern)
    -- ========================================================================
    
    -- Only hide names when class icons are actually showing (not when feature is off/hidden)
    if frame.ArenaCore_ClassIndicator and frame.ArenaCore_ClassIndicator:IsShown() then
        -- Hide name when class icon is showing (BBP pattern)
        -- BBP uses classIndicatorHideName flag which is checked in ConsolidatedUpdateName
        frame.classIndicatorHideName = true
        if frame.name then
            frame.name:SetText("")
        end
    else
        -- Restore name when class icon is hidden
        frame.classIndicatorHideName = false
    end
end

-- ============================================================================
-- REFRESH FUNCTION: Called when settings change
-- ============================================================================

function AC:RefreshPartyClassIcons()
    -- Refresh all visible nameplates
    for _, nameplate in pairs(C_NamePlate.GetNamePlates()) do
        -- Universal nameplate addon compatibility
        -- Plater/Platynator use nameplate.unitFrame (lowercase 'u')
        -- Blizzard uses nameplate.UnitFrame (uppercase 'U')
        local frame = nameplate.unitFrame or nameplate.UnitFrame
        if frame and not frame:IsForbidden() and not frame:IsProtected() then
            AC.UpdatePartyClassIndicator(frame)
        end
    end
end

-- ============================================================================
-- DEFENSIVE CLEANUP: Remove stale independent frames
-- ============================================================================
-- CRITICAL FIX: WoW recycles nameplate units (nameplate1, nameplate2, etc.)
-- If we don't clean up stale entries, icons can disappear or only show for one teammate

local function CleanupStaleFrames()
    -- Get all currently visible nameplate units
    local activeUnits = {}
    for _, nameplate in pairs(C_NamePlate.GetNamePlates()) do
        local frame = nameplate.unitFrame or nameplate.UnitFrame
        if frame and frame.unit then
            activeUnits[frame.unit] = true
        end
    end
    
    -- Remove independent frames for units that no longer exist
    for unit, frame in pairs(independentFrames) do
        -- Skip pointer frames (they have "_pointer" suffix)
        if not unit:find("_pointer") then
            -- If this unit is not in active nameplates, clean it up
            if not activeUnits[unit] then
                if frame then
                    frame:Hide()
                    frame:SetScript("OnUpdate", nil)
                end
                independentFrames[unit] = nil
                -- Also clean up associated pointer
                local pointerFrame = independentFrames[unit .. "_pointer"]
                if pointerFrame then
                    pointerFrame:Hide()
                    pointerFrame:SetScript("OnUpdate", nil)
                    independentFrames[unit .. "_pointer"] = nil
                end
            end
        end
    end
end

-- ============================================================================
-- EVENT HANDLERS: Fix health bar hiding inconsistency
-- ============================================================================
-- CRITICAL FIX: Without these events, settings don't reapply on:
-- - Entering new arena lobby (PLAYER_ENTERING_WORLD)
-- - Party composition changes (GROUP_ROSTER_UPDATE)
-- - Solo Shuffle round transitions (GROUP_ROSTER_UPDATE)

local eventFrame = CreateFrame("Frame")
eventFrame:RegisterEvent("PLAYER_ENTERING_WORLD")
eventFrame:RegisterEvent("GROUP_ROSTER_UPDATE")

eventFrame:SetScript("OnEvent", function(self, event, ...)
    -- Small delay to let Blizzard finish setting up nameplates
    C_Timer.After(0.2, function()
        -- Clean up stale frames first (prevents missing icons bug)
        CleanupStaleFrames()
        
        -- Refresh all nameplates to reapply settings
        if AC.RefreshPartyClassIcons then
            AC:RefreshPartyClassIcons()
        end
    end)
end)

-- ============================================================================
-- HOOK: Prevent Blizzard from showing names when hideNameOverride is set
-- ============================================================================

-- Hook CompactUnitFrame_UpdateName to enforce classIndicatorHideName
local function OnNameUpdate(frame)
    if not frame or not frame.unit or not frame.unit:find("nameplate") then return end
    if frame:IsForbidden() or frame:IsProtected() then return end
    
    -- If we set classIndicatorHideName, enforce it (BBP pattern)
    -- Only use SetText - let BBP handle alpha via its own system
    if frame.classIndicatorHideName and frame.name then
        frame.name:SetText("")
    end
end

-- Register the hook after a short delay to ensure CompactUnitFrame_UpdateName exists
C_Timer.After(0.1, function()
    if CompactUnitFrame_UpdateName then
        hooksecurefunc("CompactUnitFrame_UpdateName", OnNameUpdate)
    end
end)

-- ============================================================================
-- INTEGRATION: This will be called from BlackoutEngine's NAME_PLATE_UNIT_ADDED
-- ============================================================================

-- Module loaded (debug message removed for cleaner startup)
