-- Core/ClassPortraitSwap.lua
-- Swaps player portraits to class icons using ArenaCore custom assets
local AC = _G.ArenaCore
if not AC then return end

local M = {}
AC.ClassPortraitSwap = M

-- CRITICAL FIX: Throttle system to prevent error 418 (too many actions)
local pendingUpdates = {}
local updateScheduled = false

local CLASS_ICON_PATH = "Interface\\AddOns\\ArenaCore\\Media\\Classicons\\"
local CLASS_FILES = {
  DEATHKNIGHT = "Deathknight.tga",
  DEMONHUNTER = "Demonhunter.tga",
  DRUID       = "Druid.tga",
  EVOKER      = "Evoker.tga",
  HUNTER      = "Hunter.tga",
  MAGE        = "Mage.tga",
  MONK        = "Monk.tga",
  PALADIN     = "Paladin.tga",
  PRIEST      = "Priest.tga",
  ROGUE       = "Rogue.tga",
  SHAMAN      = "Shaman.tga",
  WARLOCK     = "Warlock.tga",
  WARRIOR     = "Warrior.tga",
}

local function IsEnabled()
  local db = AC.DB and AC.DB.profile and AC.DB.profile.classPortraitSwap
  return db and db.enabled
end

local function GetClassTexturePath(classToken)
  local file = classToken and CLASS_FILES[classToken]
  return file and (CLASS_ICON_PATH .. file) or nil
end

-- Reset a portrait back to the default unit portrait
local function ResetPortrait(tex, unit)
  if not tex or not unit then return end
  if _G.SetPortraitTexture then
    pcall(SetPortraitTexture, tex, unit)
  end
end

-- Apply to a single portrait texture if it's a player unit portrait
local function ApplyToPortrait(tex, unit)
  if not tex or not unit then return end
  if not IsEnabled() then return end
  if not UnitIsPlayer(unit) then return end
  local _, classToken = UnitClass(unit)
  if not classToken then return end
  local path = GetClassTexturePath(classToken)
  if path then
    -- Ensure full image and correct filtering/coloring
    tex:SetTexCoord(0, 1, 0, 1)
    tex:SetTexture(path)
    if tex.SetBlendMode then tex:SetBlendMode("BLEND") end
    if tex.SetVertexColor then tex:SetVertexColor(1, 1, 1, 1) end
    if tex.SetDesaturated then tex:SetDesaturated(false) end
    if tex.SetAlpha then tex:SetAlpha(1) end
  end
end

-- CRITICAL FIX: Batch portrait updates to prevent error 418
local function QueuePortraitUpdate(tex, unit)
  if not tex or not unit then return end
  pendingUpdates[unit] = tex
  
  if not updateScheduled then
    updateScheduled = true
    C_Timer.After(0.1, function()
      for queuedUnit, queuedTex in pairs(pendingUpdates) do
        if not InCombatLockdown() then
          ApplyToPortrait(queuedTex, queuedUnit)
        end
      end
      pendingUpdates = {}
      updateScheduled = false
    end)
  end
end

-- CRITICAL TAINT FIX: Track if hooks are active
local hooksActive = false
local hookFunctions = {}

-- Hook SetPortraitTexture (runs after Blizzard sets portrait)
local function InstallHooks()
  if M._hooked then return end
  M._hooked = true
  
  -- CRITICAL TAINT FIX: Store hook functions so we can control when they run
  hookFunctions.SetPortraitTexture = function(tex, unit)
    -- CRITICAL: Only run if hooks are active (not in combat)
    if not hooksActive then return end
    if InCombatLockdown() then return end
    -- CRITICAL FIX: Use batched queue system to prevent error 418
    QueuePortraitUpdate(tex, unit)
  end
  
  hookFunctions.SetPortraitTextureFromUnit = function(tex, unit)
    -- CRITICAL: Only run if hooks are active (not in combat)
    if not hooksActive then return end
    if InCombatLockdown() then return end
    -- CRITICAL FIX: Use batched queue system to prevent error 418
    QueuePortraitUpdate(tex, unit)
  end
  
  -- CRITICAL TAINT FIX: Disabled portrait hooks to prevent ADDON_ACTION_BLOCKED
  -- These hooks cause taint on TargetFrame's StatusBar:SetWidth() during PLAYER_TARGET_CHANGED
  -- Even with InCombatLockdown() checks, the mere existence of the hook causes taint
  -- The portrait swap feature will work via manual refresh events instead
  
  -- REMOVED TO PREVENT TAINT:
  -- pcall(function()
  --   hooksecurefunc("SetPortraitTexture", hookFunctions.SetPortraitTexture)
  --   if _G.SetPortraitTextureFromUnit then
  --     hooksecurefunc("SetPortraitTextureFromUnit", hookFunctions.SetPortraitTextureFromUnit)
  --   end
  -- end)
  
  -- Start with hooks active (will be disabled on combat start)
  hooksActive = true
end

-- Try to refresh common frames immediately
function M:RefreshAll()
  local enabled = IsEnabled()
  local try = function(frame, unitPath)
    -- CRITICAL FIX: Only apply to actual portrait textures, NOT the frame itself
    -- This prevents corrupting health bars and other frame elements
    if not frame then return end
    local tex = frame.portrait or frame.Portrait
    if not tex then return end -- Don't fall back to frame itself!
    
    if tex and unitPath then
      if enabled then
        -- Force an update by calling the API, then our hook will set the class icon
        if SetPortraitTexture then pcall(SetPortraitTexture, tex, unitPath) end
        C_Timer.After(0, function() ApplyToPortrait(tex, unitPath) end)
      else
        -- Restore original portrait
        ResetPortrait(tex, unitPath)
      end
    end
  end
  try(_G.PlayerFrame, "player")
  try(_G.TargetFrame, "target")
  try(_G.FocusFrame, "focus")
  -- Character panel button in main menu
  if _G.CharacterMicroButton then
    try(_G.CharacterMicroButton, "player")
  end
  -- Also try alternative micro button names in case of UI variations
  if _G.CharacterButton then
    try(_G.CharacterButton, "player")
  end
  for i=1,4 do try(_G["PartyMemberFrame"..i], "party"..i) end
  for i=1,5 do try(_G["Boss"..i.."TargetFrame"], "boss"..i) end
  for i=1,5 do try(_G["ArenaEnemyFrame"..i], "arena"..i) end
end

-- Initialization
local f = CreateFrame("Frame")
f:RegisterEvent("ADDON_LOADED")
f:RegisterEvent("PLAYER_LOGIN")
f:RegisterEvent("UNIT_PORTRAIT_UPDATE")
f:RegisterEvent("UNIT_MODEL_CHANGED")
f:RegisterEvent("PLAYER_ENTERING_WORLD")
-- CRITICAL TAINT FIX: Monitor combat state to disable hooks during combat
f:RegisterEvent("PLAYER_REGEN_DISABLED") -- Entering combat
f:RegisterEvent("PLAYER_REGEN_ENABLED")  -- Leaving combat

f:SetScript("OnEvent", function(_, event, arg1)
  if event == "ADDON_LOADED" and arg1 == "ArenaCore" then
    InstallHooks()
    
  elseif event == "PLAYER_LOGIN" then
    InstallHooks()
    C_Timer.After(0.5, function()
      if not InCombatLockdown() then
        M:RefreshAll()
      end
    end)
    
  -- CRITICAL TAINT FIX: Disable hooks during combat to prevent ADDON_ACTION_BLOCKED
  elseif event == "PLAYER_REGEN_DISABLED" then
    -- Entering combat - disable hooks to prevent taint
    hooksActive = false
    
  elseif event == "PLAYER_REGEN_ENABLED" then
    -- Leaving combat - re-enable hooks and refresh portraits
    hooksActive = true
    C_Timer.After(0.1, function()
      if not InCombatLockdown() then
        M:RefreshAll()
      end
    end)
    
  elseif event == "UNIT_PORTRAIT_UPDATE" then
    -- CRITICAL FIX: Reapply class icon when portrait updates (debuffs can trigger this)
    -- Don't run during combat to prevent ADDON_ACTION_BLOCKED
    if InCombatLockdown() then return end
    if not hooksActive then return end
    
    if arg1 == "player" and IsEnabled() then
      -- CRITICAL FIX: Check for both portrait and Portrait (case-sensitive)
      local frame = _G.PlayerFrame
      if not frame then return end
      local tex = frame.portrait or frame.Portrait
      if tex then
        -- CRITICAL FIX: Use batched queue system to prevent error 418
        QueuePortraitUpdate(tex, "player")
      end
    elseif arg1 == "target" and IsEnabled() then
      -- CRITICAL FIX: Check for both portrait and Portrait (case-sensitive)
      local frame = _G.TargetFrame
      if not frame then return end
      local tex = frame.portrait or frame.Portrait
      if tex then
        -- CRITICAL FIX: Use batched queue system to prevent error 418
        QueuePortraitUpdate(tex, "target")
      end
    elseif arg1 == "focus" and IsEnabled() then
      -- CRITICAL FIX: Check for both portrait and Portrait (case-sensitive)
      local frame = _G.FocusFrame
      if not frame then return end
      local tex = frame.portrait or frame.Portrait
      if tex then
        -- CRITICAL FIX: Use batched queue system to prevent error 418
        QueuePortraitUpdate(tex, "focus")
      end
    end
  elseif event == "UNIT_MODEL_CHANGED" then
    -- CRITICAL FIX: Reapply when model changes (can affect portrait)
    -- Don't run during combat to prevent ADDON_ACTION_BLOCKED
    if InCombatLockdown() then return end
    
    if arg1 == "player" and IsEnabled() then
      local frame = _G.PlayerFrame
      if not frame then return end
      local tex = frame.portrait or frame.Portrait
      if tex then
        -- CRITICAL FIX: Use batched queue system to prevent error 418
        QueuePortraitUpdate(tex, "player")
      end
    end
  elseif event == "PLAYER_ENTERING_WORLD" then
    -- CRITICAL FIX: Reapply when entering arena (fixes debuff persistence from previous game)
    -- Use longer delay to avoid error 418 during zone transitions
    C_Timer.After(1.0, function()
      if not InCombatLockdown() then
        M:RefreshAll()
      end
    end)
  end
end)
