-- ============================================================================
-- File: ArenaCore/Core/PartyClassIndicators.lua (v1.0)
-- Purpose: Party class indicators that show class icons above players' heads
-- ============================================================================

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

-- Storage for created indicators
local partyIndicators = {}
local allPlayerIndicators = {}
local updateFrame = nil

-- Use Blizzard's normal nameplate font object (prevents Name-Only mode font)
local NORMAL_NAMEPLATE_FONT = SystemFont_NamePlate or SystemFont_NamePlateFixed

-- Name hider for NPCs (handles "fake name" FontStrings from other addons)
local function StripColors(s)
    return s and s:gsub("|c%x%x%x%x%x%x%x%x", ""):gsub("|r", "") or s
end

local function _cacheNameStrings(frame)
    if frame.__acAltNameFS then return end
    frame.__acAltNameFS = {}

    local unitName = UnitName(frame.unit)
    local plain = StripColors(unitName or "")
    if plain == "" then return end

    local function maybeStore(fs)
        if fs and fs.IsObjectType and fs:IsObjectType("FontString") then
            -- CRITICAL: Don't cache frame.name itself (we handle that separately)
            if fs == frame.name then return end
            
            local t = fs:GetText()
            if t and t ~= "" then
                local tp = StripColors(t)
                if tp == plain or tp:find(plain, 1, true) then
                    table.insert(frame.__acAltNameFS, fs)
                end
            end
        end
    end

    -- Scan the plate regions
    for i = 1, select("#", frame:GetRegions()) do
        maybeStore(select(i, frame:GetRegions()))
    end
    -- Scan direct children (common for "fake name" overlays)
    for i = 1, frame:GetNumChildren() do
        local child = select(i, frame:GetChildren())
        if child and child.GetRegions then
            for j = 1, select("#", child:GetRegions()) do
                maybeStore(select(j, child:GetRegions()))
            end
        end
    end
end

local function HideAllNamesForNPC(frame)
    if not frame then return end
    _cacheNameStrings(frame)

    if frame.name then
        frame.name:SetText("")
        frame.name:Hide()
        frame.name:SetAlpha(0)
    end
    if frame.__acAltNameFS then
        for _, fs in ipairs(frame.__acAltNameFS) do
            fs:SetText("")
            fs:Hide()
            fs:SetAlpha(0)
        end
    end
end

local function RestoreAllNames(frame)
    if not frame then return end
    -- Show any cached "fake names" again when the plate becomes a player
    if frame.__acAltNameFS then
        for _, fs in ipairs(frame.__acAltNameFS) do
            fs:Show()
            fs:SetAlpha(1)
        end
        frame.__acAltNameFS = nil
    end
    if frame.name then
        frame.name:Show()
        frame.name:SetAlpha(1)
    end
end

-- CRITICAL: Protect name from inheriting parent scale
local function EnsureStableName(frame)
    if not frame or not frame.name then return end
    -- CRITICAL: Validate frame has GetScale method (garrison/non-nameplate frames may not)
    if not frame.GetScale then return end
    -- Read the plate's current scale (varies with distance & CVars)
    local parentScale = frame:GetScale() or 1
    frame.name:SetIgnoreParentScale(true)
    -- Apply the *same* scale the parent has, so the visual size matches baseline
    frame.name:SetScale(parentScale)
    
    -- CRITICAL: Reset to normal font to prevent Name-Only mode large font
    if NORMAL_NAMEPLATE_FONT then
        frame.name:SetFontObject(NORMAL_NAMEPLATE_FONT)
    end
end

local function RestoreNameDefaults(frame)
    if not frame or not frame.name then return end
    frame.__acNameHidden = nil
    -- Keep the protection on (avoid future inheritance explosions),
    -- but match baseline by mirroring parent scale.
    local parentScale = frame:GetScale() or 1
    frame.name:SetIgnoreParentScale(true)
    frame.name:SetScale(parentScale)
    
    -- CRITICAL: Reset to Blizzard's normal nameplate font to avoid "stuck large"
    if NORMAL_NAMEPLATE_FONT then
        frame.name:SetFontObject(NORMAL_NAMEPLATE_FONT)
    end
end

-- Class icon paths
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",
}

-- Create a class indicator frame
local function CreateClassIndicator(frame)
    if frame.ArenaCore_ClassIndicator then return end
    
    -- Create the main indicator frame
    frame.ArenaCore_ClassIndicator = CreateFrame("Frame", nil, frame)
    frame.ArenaCore_ClassIndicator:SetSize(32, 32)
    frame.ArenaCore_ClassIndicator:SetIgnoreParentAlpha(true)
    
    -- CRITICAL: Clear name hiding flag when class indicator hides
    frame.ArenaCore_ClassIndicator:HookScript("OnHide", function()
        frame.__acNameHidden = nil
    end)
    
    -- Create the class icon texture
    frame.ArenaCore_ClassIndicator.icon = frame.ArenaCore_ClassIndicator:CreateTexture(nil, "ARTWORK")
    frame.ArenaCore_ClassIndicator.icon:SetPoint("CENTER", frame.ArenaCore_ClassIndicator)
    frame.ArenaCore_ClassIndicator.icon:SetSize(28, 28)
    
    -- Create circular mask
    frame.ArenaCore_ClassIndicator.mask = frame.ArenaCore_ClassIndicator:CreateMaskTexture()
    frame.ArenaCore_ClassIndicator.mask:SetTexture("Interface\\CharacterFrame\\TempPortraitAlphaMask", "CLAMPTOBLACKADDITIVE", "CLAMPTOBLACKADDITIVE")
    frame.ArenaCore_ClassIndicator.mask:SetSize(28, 28)
    frame.ArenaCore_ClassIndicator.mask:SetPoint("CENTER", frame.ArenaCore_ClassIndicator.icon)
    frame.ArenaCore_ClassIndicator.icon:AddMaskTexture(frame.ArenaCore_ClassIndicator.mask)
    
    -- Create border using BlackOutline.tga
    frame.ArenaCore_ClassIndicator.border = frame.ArenaCore_ClassIndicator:CreateTexture(nil, "OVERLAY")
    frame.ArenaCore_ClassIndicator.border:SetAllPoints(frame.ArenaCore_ClassIndicator)
    frame.ArenaCore_ClassIndicator.border:SetTexture("Interface\\AddOns\\ArenaCore\\Media\\Classicons\\BlackOutline.tga")
    
    -- Position above nameplate (fallback to frame if name region doesn't exist)
    if frame.name then
        frame.ArenaCore_ClassIndicator:SetPoint("BOTTOM", frame.name, "TOP", 0, 8)
    else
        frame.ArenaCore_ClassIndicator:SetPoint("BOTTOM", frame, "TOP", 0, 8)
    end
    frame.ArenaCore_ClassIndicator:Hide()
    
    -- CRITICAL: Create triangle pointer (separate from class icon)
    frame.ArenaCore_Pointer = CreateFrame("Frame", nil, frame)
    frame.ArenaCore_Pointer:SetSize(34, 48)
    frame.ArenaCore_Pointer:SetIgnoreParentAlpha(true)
    
    -- Create pointer texture (downward triangle arrow)
    frame.ArenaCore_Pointer.icon = frame.ArenaCore_Pointer:CreateTexture(nil, "ARTWORK")
    frame.ArenaCore_Pointer.icon:SetAtlas("UI-QuestPoiImportant-QuestNumber-SuperTracked")
    frame.ArenaCore_Pointer.icon:SetSize(34, 48)
    frame.ArenaCore_Pointer.icon:SetPoint("BOTTOM", frame.ArenaCore_Pointer, "BOTTOM", 0, 5)
    frame.ArenaCore_Pointer.icon:SetDesaturated(true) -- Allow coloring
    frame.ArenaCore_Pointer.icon:SetTexelSnappingBias(0.0) -- Reduce pixelation
    frame.ArenaCore_Pointer.icon:SetSnapToPixelGrid(false) -- Smoother scaling
    
    -- Color based on class (will be set during update)
    frame.ArenaCore_Pointer.icon:SetVertexColor(1, 1, 1, 1)
    
    -- Position above nameplate
    if frame.name then
        frame.ArenaCore_Pointer:SetPoint("BOTTOM", frame.name, "TOP", 0, 40)
    else
        frame.ArenaCore_Pointer:SetPoint("BOTTOM", frame, "TOP", 0, 40)
    end
    frame.ArenaCore_Pointer:Hide()
end

-- Check if a unit is a healer based on their spec
local function IsHealer(unit)
    if not unit or not UnitExists(unit) then return false end
    -- Prefer group role assignment which is reliable for party/raid units
    local role = UnitGroupRolesAssigned and UnitGroupRolesAssigned(unit)
    if role and role ~= "NONE" then
        return role == "HEALER"
    end
    -- Fallbacks: if unit is the player, use player's spec role
    if UnitIsUnit(unit, "player") then
        local playerSpec = GetSpecialization and GetSpecialization()
        if playerSpec then
            local r = GetSpecializationRole(playerSpec)
            return r == "HEALER"
        end
    end
    -- As a last resort, try inspect specialization if available (may be 0 for nameplates)
    if GetInspectSpecialization then
        local specID = GetInspectSpecialization(unit)
        if specID and specID ~= 0 then
            local _, _, _, _, r = GetSpecializationInfoByID(specID)
            return r == "HEALER"
        end
    end
    return false
end

-- Try to resolve a nameplate unit into a party/raid/player unit token by GUID
local function ResolveGroupUnit(unit)
    if not unit or not UnitExists(unit) then return nil end
    -- If it's already a direct group token, return as-is
    if unit:find("^party%d$") or unit:find("^raid%d+$") or unit == "player" then
        return unit
    end
    local guid = UnitGUID(unit)
    if not guid then return nil end
    -- Check player
    if UnitGUID("player") == guid then return "player" end
    -- Check party1-4
    for i = 1, 4 do
        local token = "party"..i
        if UnitExists(token) and UnitGUID(token) == guid then
            return token
        end
    end
    -- If in raid, also scan raid units (limited scan for performance)
    for i = 1, 40 do
        local token = "raid"..i
        if UnitExists(token) and UnitGUID(token) == guid then
            return token
        end
    end
    return nil
end

-- Check if player is the healer (to auto-disable feature)
local function IsPlayerHealer()
    local role = GetSpecializationRole(GetSpecialization() or 1)
    return role == "HEALER"
end

-- Update class indicator for a nameplate frame
local function UpdateClassIndicator(frame)
    -- CRITICAL: Basic validation
    if not frame or not frame.unit then
        if frame.ArenaCore_ClassIndicator then
            frame.ArenaCore_ClassIndicator:Hide()
        end
        return
    end
    
    -- CRITICAL: Double-check for NPCs
    local isPlayer = UnitIsPlayer(frame.unit)
    local _, class = UnitClass(frame.unit)
    
    -- CRITICAL: If this plate was an NPC but is now a player, restore fake names
    if isPlayer and class and frame.__acAltNameFS then
        RestoreAllNames(frame)
    end
    
    -- CRITICAL: If not a player OR no class, it's an NPC - restore everything and return
    if not isPlayer or not class then
        if frame.ArenaCore_ClassIndicator then
            frame.ArenaCore_ClassIndicator:Hide()
        end
        if frame.ArenaCore_Pointer then
            frame.ArenaCore_Pointer:Hide()
        end
        
        -- CRITICAL FIX: DON'T touch health bars for NPCs - let WoW handle it!
        -- The previous code was causing white/transparent health bars
        -- Just restore any hidden health bars if we previously hid them
        if frame.__acHealthHidden and frame.HealthBarsContainer then
            frame.HealthBarsContainer:SetAlpha(1)
            if frame.selectionHighlight then
                frame.selectionHighlight:SetAlpha(1)
            end
            frame.__acHealthHidden = nil
        end
        
        -- CRITICAL: Restore name defaults (scale + font)
        RestoreNameDefaults(frame)
        
        -- CRITICAL FIX: Only hide NPC names if the feature is enabled
        -- Check the UI setting before hiding names
        local moreGoodiesDB = AC.DB and AC.DB.profile and AC.DB.profile.moreGoodies
        if moreGoodiesDB and moreGoodiesDB.partyClassSpecs and moreGoodiesDB.partyClassSpecs.mode ~= "off" then
            -- Feature is enabled - hide NPC names for cleaner UI
            HideAllNamesForNPC(frame)
        else
            -- Feature is disabled - restore NPC names so they're visible
            RestoreAllNames(frame)
        end
        
        return
    end
    
    -- CRITICAL: Never show on player's own nameplate
    if UnitIsUnit(frame.unit, "player") then
        if frame.ArenaCore_ClassIndicator then
            frame.ArenaCore_ClassIndicator:Hide()
        end
        if frame.ArenaCore_Pointer then
            frame.ArenaCore_Pointer:Hide()
        end
        return
    end
    
    -- Get settings
    local moreGoodiesDB = AC.DB and AC.DB.profile and AC.DB.profile.moreGoodies
    if not moreGoodiesDB or not moreGoodiesDB.partyClassSpecs then return end
    
    local mode = moreGoodiesDB.partyClassSpecs.mode
    if mode == "off" then
        if frame.ArenaCore_ClassIndicator then
            frame.ArenaCore_ClassIndicator:Hide()
        end
        -- Health bars will be restored automatically
        return
    end
    
    -- Check if we should show for this unit
    local showForThisUnit = false
    local groupUnitForThis = ResolveGroupUnit(frame.unit)
    
    -- CRITICAL FIX: Never show on arena enemies (arena1, arena2, arena3)
    local isArenaEnemy = frame.unit and frame.unit:match("^arena%d$")
    
    if mode == "party" then
        -- Only show for party/raid members (resolve by GUID from nameplates)
        showForThisUnit = groupUnitForThis ~= nil and not isArenaEnemy
    elseif mode == "all" then
        -- Show for friendly players only (but NOT arena enemies)
        -- FIXED: Use more robust friendly check - reaction >= 5 OR UnitIsFriend
        local reaction = UnitReaction(frame.unit, "player")
        local isFriendlyByReaction = reaction and reaction >= 5
        local isFriendlyByAPI = UnitIsFriend("player", frame.unit)
        showForThisUnit = (isFriendlyByReaction or isFriendlyByAPI) and not isArenaEnemy
    end
    
    if not showForThisUnit then
        if frame.ArenaCore_ClassIndicator then
            frame.ArenaCore_ClassIndicator:Hide()
        end
        if frame.ArenaCore_Pointer then
            frame.ArenaCore_Pointer:Hide()
        end
        
        -- CRITICAL: Restore health bars if we previously hid them
        if frame.__acHealthHidden and frame.HealthBarsContainer then
            frame.HealthBarsContainer:SetAlpha(1)
            if frame.selectionHighlight then
                frame.selectionHighlight:SetAlpha(1)
            end
            frame.__acHealthHidden = nil
        end
        
        -- CRITICAL: Restore name defaults when not showing indicators
        RestoreNameDefaults(frame)
        -- Note: Don't call RestoreAllNames here - that's only for NPC->Player recycling
        return
    end
    
    -- Create indicator if it doesn't exist
    CreateClassIndicator(frame)
    
    -- Prefer the resolved group unit for class/role data if available
    local unitForData = groupUnitForThis or frame.unit
    local _, class = UnitClass(unitForData)
    if not class then
        frame.ArenaCore_ClassIndicator:Hide()
        return
    end
    
    -- Check for healer icon
    local showHealerIcon = moreGoodiesDB.partyClassSpecs.showHealerIcon
    local iconPath
    
    -- REFINED LOGIC: Where's My Healer feature
    if showHealerIcon and IsHealer(unitForData) then
        -- CRITICAL: If USER is the healer, nullify entire feature (avoid errors)
        if IsPlayerHealer() then
            -- User is the healer, their teammates are DPS - show normal class icons
            iconPath = CLASS_ICON_PATHS[class]
        else
            -- User is DPS, looking for their team's healer
            -- ONLY show healer icon for PARTY/FRIENDLY healers (not enemies)
            if groupUnitForThis and not UnitIsUnit(unitForData, "player") then
                -- This is a party/raid member healer - show special healer icon
                iconPath = "Interface\\AddOns\\ArenaCore\\Media\\Classicons\\HealerPointer"
            else
                -- This is an enemy healer or not a group member - show normal class icon
                iconPath = CLASS_ICON_PATHS[class]
            end
        end
    else
        -- Normal class icon for non-healers or when feature is disabled
        iconPath = CLASS_ICON_PATHS[class]
    end
    
    if iconPath then
        frame.ArenaCore_ClassIndicator.icon:SetTexture(iconPath)
        frame.ArenaCore_ClassIndicator.icon:SetTexCoord(0.05, 0.95, 0.05, 0.95)
        
        -- Apply scale for class/healer icons (same settings for both)
        local finalScale
        do
            local pm = AC.ProfileManager
            local scalePixels = pm and pm.GetSetting and pm:GetSetting("moreGoodies.partyClassSpecs.scale")
            if type(scalePixels) == "number" then
                -- Convert stored pixels to scale 1..12 using enhanced preset (50..360 px)
                local currentScale = AC.ConvertPixelsToScale and AC:ConvertPixelsToScale(scalePixels, 50, 360, 1, 12) or 6.5
                -- Map 1..12 -> 0.5..3.0 (11 steps)
                finalScale = 0.5 + (currentScale - 1) * (2.5 / 11)
            else
                -- Fallback legacy DB value (1..12 or 50..300)
                local rawScale = (moreGoodiesDB.partyClassSpecs and moreGoodiesDB.partyClassSpecs.scale) or 100
                if rawScale <= 12 then
                    -- Map 1..12 -> 0.5..3.0
                    finalScale = 0.5 + (rawScale - 1) * (2.5 / 11)
                else
                    -- Percent-like legacy value, allow up to 300%
                    finalScale = rawScale / 100
                end
            end
            -- Clamp to 0.5..3.0
            finalScale = math.max(0.5, math.min(finalScale or 1.0, 3.0))
            frame.ArenaCore_ClassIndicator:SetScale(finalScale)
        end

        -- Apply horizontal/vertical offsets for class/healer icons (same settings for both)
        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 = (moreGoodiesDB.partyClassSpecs and moreGoodiesDB.partyClassSpecs.offsetX) or 0
            end
            if type(py) ~= "number" then
                py = (moreGoodiesDB.partyClassSpecs and moreGoodiesDB.partyClassSpecs.offsetY) or 0
            end
            offX, offY = tonumber(px) or 0, tonumber(py) or 0
        end
        -- base offset above the nameplate for visibility
        local baseY = 8
        frame.ArenaCore_ClassIndicator:ClearAllPoints()
        if frame.name then
            frame.ArenaCore_ClassIndicator:SetPoint("BOTTOM", frame.name, "TOP", offX, baseY + offY)
        else
            frame.ArenaCore_ClassIndicator:SetPoint("BOTTOM", frame, "TOP", offX, baseY + offY)
        end
        
        frame.ArenaCore_ClassIndicator:Show()
        
        -- CRITICAL: Protect name from inheriting indicator scale
        EnsureStableName(frame)
        
        -- CRITICAL: Update pointer (triangle arrow) with separate positioning
        -- ONLY show pointers for FRIENDLY units (party/raid members), NOT enemies or pets
        local showPointers = moreGoodiesDB.partyClassSpecs.showPointers
        local isPlayer = UnitIsPlayer(unitForData) -- Exclude pets/guardians
        
        -- CRITICAL: Use UnitReaction for friendly check (reaction >= 5 = friendly)
        -- In arena, enemy players have reaction < 4, so this properly excludes them
        local reaction = UnitReaction(unitForData, "player")
        local isFriendly = reaction and reaction >= 5
        
        -- CRITICAL FIX: Check if unit is NPC (test dummy, training dummy, etc.)
        -- Test dummies return true for UnitIsPlayer() but false for UnitPlayerControlled()
        local isNPC = not UnitPlayerControlled(unitForData)
        
        -- Show pointers for friendly players, but exclude NPCs (test dummies)
        if frame.ArenaCore_Pointer and showPointers ~= false and isFriendly and isPlayer and not isNPC then
            -- 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 = (moreGoodiesDB.partyClassSpecs and moreGoodiesDB.partyClassSpecs.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))
                frame.ArenaCore_Pointer: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 = (moreGoodiesDB.partyClassSpecs and moreGoodiesDB.partyClassSpecs.pointerOffsetX) or 0
                end
                if type(py) ~= "number" then
                    py = (moreGoodiesDB.partyClassSpecs and moreGoodiesDB.partyClassSpecs.pointerOffsetY) or 0
                end
                ptrOffX, ptrOffY = tonumber(px) or 0, tonumber(py) or 0
            end
            
            -- Position pointer above class icon
            local basePointerY = 40
            frame.ArenaCore_Pointer:ClearAllPoints()
            if frame.name then
                frame.ArenaCore_Pointer:SetPoint("BOTTOM", frame.name, "TOP", ptrOffX, basePointerY + ptrOffY)
            else
                frame.ArenaCore_Pointer:SetPoint("BOTTOM", frame, "TOP", ptrOffX, basePointerY + ptrOffY)
            end
            
            -- Color pointer based on class
            if class and RAID_CLASS_COLORS[class] then
                local classColor = RAID_CLASS_COLORS[class]
                frame.ArenaCore_Pointer.icon:SetVertexColor(classColor.r, classColor.g, classColor.b, 1)
            end
            
            frame.ArenaCore_Pointer:Show()
        elseif frame.ArenaCore_Pointer then
            -- Hide pointer if setting is disabled
            frame.ArenaCore_Pointer:Hide()
        end
        
        -- CRITICAL FIX: Hide friendly health bars ONLY if setting is enabled
        -- SIMPLIFIED: More safety checks to prevent hiding enemy health bars
        local hideHealthBars = moreGoodiesDB.partyClassSpecs.hideHealthBars
        
        -- CRITICAL: Multiple checks to ensure we NEVER hide enemy health bars
        local shouldHide = false
        if hideHealthBars and unitForData and UnitExists(unitForData) then
            -- Check 1: Must be friendly
            local isFriendly = UnitIsFriend("player", unitForData)
            -- Check 2: Must NOT be an enemy player
            local isEnemyPlayer = UnitIsPlayer(unitForData) and UnitIsEnemy("player", unitForData)
            -- Check 3: Must NOT be in arena (arena units should NEVER have hidden health bars)
            local isArenaUnit = string.match(unitForData or "", "^arena%d")
            
            -- Only hide if friendly AND not enemy player AND not arena unit
            shouldHide = isFriendly and not isEnemyPlayer and not isArenaUnit
        end
        
        if shouldHide and frame.HealthBarsContainer then
            -- Only hide health bars for FRIENDLY units (party/raid members)
            frame.HealthBarsContainer:SetAlpha(0)
            if frame.selectionHighlight then
                frame.selectionHighlight:SetAlpha(0)
            end
            frame.__acHealthHidden = true
        else
            -- CRITICAL FIX: ALWAYS ensure health bars are visible for non-friendly units
            -- This prevents the faint/transparent health bar bug
            if frame.HealthBarsContainer then
                frame.HealthBarsContainer:SetAlpha(1)
            end
            if frame.selectionHighlight then
                frame.selectionHighlight:SetAlpha(1)
            end
            if frame.__acHealthHidden then
                frame.__acHealthHidden = nil
            end
        end
        
        -- SIMPLE: Hide names when targeted/selected
        -- The class indicator is showing, so we can hide the name
        local isTargeted = UnitIsUnit(unitForData, "target")
        local isSelected = frame.selectionHighlight and frame.selectionHighlight:IsShown()
        
        if frame.name then
            -- CRITICAL: Only hide names for players (never NPCs)
            local _, classForName = UnitClass(unitForData)
            local isPlayerUnit = classForName ~= nil
            
            -- FIXED: Use alpha instead of SetText("") to preserve the name text
            -- This allows Blizzard's nameplate system to properly restore names
            if isPlayerUnit and (isTargeted or isSelected) then
                frame.__acNameHidden = true
                frame.name:SetAlpha(0)
            else
                frame.__acNameHidden = nil
                frame.name:SetAlpha(1)
                -- CRITICAL: Ensure normal font whenever we're showing
                if NORMAL_NAMEPLATE_FONT then
                    frame.name:SetFontObject(NORMAL_NAMEPLATE_FONT)
                end
            end
        end
    else
        frame.ArenaCore_ClassIndicator:Hide()
        
        -- Hide pointer when class icons are hidden
        if frame.ArenaCore_Pointer then
            frame.ArenaCore_Pointer:Hide()
        end
        
        -- OnHide hook will clear flags automatically
    end
    
    -- CRITICAL FINAL SAFEGUARD: Ensure enemy health bars are ALWAYS visible
    -- This prevents the faint/transparent health bar bug on enemies
    if frame.unit and UnitExists(frame.unit) then
        local isEnemy = UnitIsEnemy("player", frame.unit)
        if isEnemy and frame.HealthBarsContainer then
            -- Force health bars visible for ALL enemies
            frame.HealthBarsContainer:SetAlpha(1)
            if frame.selectionHighlight then
                frame.selectionHighlight:SetAlpha(1)
            end
        end
    end
end

-- Clean up indicators for units that no longer exist
local function CleanupIndicators(indicatorTable)
    for unit, indicator in pairs(indicatorTable) do
        if not UnitExists(unit) or not C_NamePlate.GetNamePlateForUnit(unit) then
            indicator:Hide()
            indicator:SetParent(nil)
            indicatorTable[unit] = nil
        end
    end
end

-- Handle nameplate added
local function HandleNamePlateAdded(unit)
    local nameplate = C_NamePlate.GetNamePlateForUnit(unit)
    if not nameplate then return end
    
    local frame = nameplate.UnitFrame
    if not frame then return end
    
    -- Update the class indicator for this frame
    UpdateClassIndicator(frame)
end

-- Handle nameplate removed
local function HandleNamePlateRemoved(unit)
    local nameplate = C_NamePlate.GetNamePlateForUnit(unit)
    if nameplate and nameplate.UnitFrame then
        local f = nameplate.UnitFrame
        if f.ArenaCore_ClassIndicator then
            f.ArenaCore_ClassIndicator:Hide()
        end
        -- Clear our cached refs so the next unit starts clean
        f.__acAltNameFS = nil
    end
end

-- Refresh all visible nameplates
local function RefreshAllNameplates()
    local nameplates = C_NamePlate.GetNamePlates()
    for _, nameplate in ipairs(nameplates) do
        if nameplate.UnitFrame and nameplate.UnitFrame.unit then
            UpdateClassIndicator(nameplate.UnitFrame)
        end
    end
end

-- Main update function (now just refreshes all nameplates)
local function UpdateClassIndicators()
    RefreshAllNameplates()
end

-- Emergency cleanup function to fix massive icon bug
AC.EmergencyCleanupClassIcons = function()
    print("|cffFF0000ArenaCore:|r EMERGENCY CLEANUP - Hiding all class icons!")
    
    -- Hide all party indicators
    for unit, indicator in pairs(partyIndicators) do
        if indicator then
            indicator:Hide()
            indicator:SetSize(32, 32) -- Reset to default size
        end
    end
    
    -- Hide all player indicators  
    for unit, indicator in pairs(allPlayerIndicators) do
        if indicator then
            indicator:Hide()
            indicator:SetSize(32, 32) -- Reset to default size
        end
    end
    
    print("|cffFF0000ArenaCore:|r Emergency cleanup complete! Try /reload if issues persist.")
end

-- Refresh party class icons (called from UI)
AC.RefreshPartyClassIcons = function()
    RefreshAllNameplates()
end

-- Initialize the system
AC.InitializePartyClassIndicators = function()
    if AC.PartyClassIndicators_Initialized then return end
    
    -- Event frame for nameplate events
    local eventFrame = CreateFrame("Frame")
    eventFrame:RegisterEvent("NAME_PLATE_UNIT_ADDED")
    eventFrame:RegisterEvent("NAME_PLATE_UNIT_REMOVED")
    eventFrame:RegisterEvent("GROUP_ROSTER_UPDATE")
    eventFrame:RegisterEvent("PLAYER_ENTERING_WORLD")
    -- DISABLED: PLAYER_TARGET_CHANGED causes TargetFrame errors
    -- NAME_PLATE_UNIT_ADDED and other events are sufficient
    -- eventFrame:RegisterEvent("PLAYER_TARGET_CHANGED")
    
    eventFrame:SetScript("OnEvent", function(self, event, unit)
        if event == "NAME_PLATE_UNIT_ADDED" then
            HandleNamePlateAdded(unit)
        elseif event == "NAME_PLATE_UNIT_REMOVED" then
            HandleNamePlateRemoved(unit)
        elseif event == "GROUP_ROSTER_UPDATE" or event == "PLAYER_ENTERING_WORLD" then
            C_Timer.After(0.1, RefreshAllNameplates)
            -- FIXED: Add additional delayed refresh to catch late-loading nameplates
            C_Timer.After(0.5, RefreshAllNameplates)
        end
        -- PLAYER_TARGET_CHANGED handler removed - event disabled to prevent TargetFrame errors
    end)
    
    AC.PartyClassIndicators_Initialized = true
end

-- Cleanup function
local function CleanupAllIndicators()
    for unit, indicator in pairs(partyIndicators) do
        indicator:Hide()
        indicator:SetParent(nil)
    end
    for unit, indicator in pairs(allPlayerIndicators) do
        indicator:Hide()
        indicator:SetParent(nil)
    end
    partyIndicators = {}
    allPlayerIndicators = {}
end

-- Public functions
function AC:UpdatePartyClassIndicators()
    UpdateClassIndicators()
end

function AC:CleanupPartyClassIndicators()
    CleanupAllIndicators()
end

-- Debug function to force update (can be called from chat)
function AC:ForceUpdatePartyClassIndicators()
    UpdateClassIndicators()
end

-- Hook into WoW's nameplate name update function
-- This ensures names stay hidden even when WoW tries to update them
local function OnNameUpdate(frame)
    -- CRITICAL TAINT FIX: Don't run during combat to prevent ADDON_ACTION_BLOCKED
    -- CompactUnitFrame_UpdateName is called by Blizzard during combat and can taint TargetFrame
    if InCombatLockdown() then return end
    
    if not frame or not frame.unit then return end
    
    -- CRITICAL: Always protect the name from parent scale
    EnsureStableName(frame)
    
    -- CRITICAL: Double-check for NPCs using UnitIsPlayer
    local isPlayer = UnitIsPlayer(frame.unit)
    local _, class = UnitClass(frame.unit)
    
    if not isPlayer or not class then
        -- CRITICAL FIX: Only hide NPC names if feature is enabled
        -- Check the UI setting before hiding names
        local moreGoodiesDB = AC.DB and AC.DB.profile and AC.DB.profile.moreGoodies
        if moreGoodiesDB and moreGoodiesDB.partyClassSpecs and moreGoodiesDB.partyClassSpecs.mode ~= "off" then
            -- Feature is enabled - hide NPC names
            HideAllNamesForNPC(frame)
        else
            -- Feature is disabled - restore NPC names
            RestoreAllNames(frame)
        end
        return
    end
    
    -- Player logic: hide names when flag is set
    if frame.__acNameHidden then
        if frame.name then
            -- FIXED: Use alpha instead of SetText("") to preserve name text
            frame.name:SetAlpha(0)
        end
    else
        -- FIXED: Restore alpha when not hidden
        if frame.name then
            frame.name:SetAlpha(1)
        end
    end
end

-- Auto-initialize when the addon loads
C_Timer.After(1, function()
    AC.InitializePartyClassIndicators()
    
    -- CRITICAL TAINT FIX: Disabled CompactUnitFrame_UpdateName hook
    -- This hook causes ADDON_ACTION_BLOCKED errors because Blizzard calls
    -- CompactUnitFrame_UpdateName during combat for TargetFrame and other protected frames.
    -- Even with InCombatLockdown() checks, the mere existence of the hook causes taint.
    -- The nameplate hiding feature will work via NAME_PLATE_UNIT_ADDED events instead.
    
    -- REMOVED TO PREVENT TAINT:
    -- if CompactUnitFrame_UpdateName then
    --     hooksecurefunc("CompactUnitFrame_UpdateName", OnNameUpdate)
    -- end
end)
