-- ============================================================================
-- MismatchHandler
-- Keeps frame visibility sane in weird brackets (2v3, 1v2, etc.)
-- Preserves correct class data and prevents incorrect data from being applied
-- when Blizzard's arena APIs return stale or inconsistent information.
-- ============================================================================

local AddonName, AC = ...

-- Create module
local MismatchHandler = {}
AC.MismatchHandler = MismatchHandler

-- Local references for performance
local GetArenaOpponentSpec = GetArenaOpponentSpec
local GetNumArenaOpponentSpecs = GetNumArenaOpponentSpecs
local GetSpecializationInfoByID = GetSpecializationInfoByID
local UnitClass = UnitClass
local UnitExists = UnitExists
local UnitGUID = UnitGUID
local IsActiveBattlefieldArena = IsActiveBattlefieldArena
local IsInInstance = IsInInstance
local InCombatLockdown = InCombatLockdown
local C_Timer = C_Timer
local wipe = wipe
local MAX_ARENA_ENEMIES = 5

-- Event frame
local eventFrame = CreateFrame("Frame")

-- ============================================================================
-- CLASS DATA PRESERVATION
-- ============================================================================

-- Track which arena units have valid class data detected
local seenValidClassData = {}

-- Track which units have been seen (for older clients where UnitExists may return false)
local seenArenaUnits = {}

-- Store last known valid class for each arena unit
local lastKnownClass = {}

-- Store last known valid spec for each arena unit
local lastKnownSpec = {}

-- Store last known valid spec texture for each arena unit
local lastKnownSpecTexture = {}

-- Store last known valid spec ID for each arena unit
local lastKnownSpecID = {}

-- Track if we're in a match (for proper state management)
local isInArenaMatch = false

-- Track if we're in preparation room
local isInPrepRoom = false

-- ============================================================================
-- UNIT VALIDATION
-- ============================================================================

local function IsValidUnit(unit)
    if not unit then
        return false
    end
    
    -- Validate it's an arena unit (arena1-arena5)
    local unitID = unit:match("arena(%d+)")
    return unitID and tonumber(unitID) <= 5
end

-- ============================================================================
-- STATE MANAGEMENT
-- ============================================================================

local function ResetState()
    -- Reset all tracking tables when leaving arena
    wipe(seenValidClassData)
    wipe(seenArenaUnits)
    wipe(lastKnownClass)
    wipe(lastKnownSpec)
    wipe(lastKnownSpecTexture)
    wipe(lastKnownSpecID)
    
    isInArenaMatch = false
    isInPrepRoom = false
end

-- ============================================================================
-- CLASS DATA TRACKING
-- ============================================================================

-- Update tracking for a specific arena unit
local function UpdateClassDataTracking(arenaIndex, unit)
    if not unit then return end
    
    local unitExists = UnitExists(unit)
    
    -- For older clients, track seen units even when UnitExists returns false
    if AC.isTBC or AC.isWrath then
        if unitExists then
            seenArenaUnits[arenaIndex] = true
        end
    end
    
    -- Get current class data
    local currentClass, currentClassFile = UnitClass(unit)
    local currentSpecID = GetArenaOpponentSpec and GetArenaOpponentSpec(arenaIndex) or 0
    
    -- Only update our stored data if we have valid new information
    -- This is the key: we DON'T overwrite valid data with invalid data
    if unitExists and currentClassFile then
        -- Check if spec data is valid
        if currentSpecID and currentSpecID > 0 then
            local id, name, description, icon, role, class = GetSpecializationInfoByID(currentSpecID)
            
            if class then
                -- Store valid class data
                lastKnownClass[arenaIndex] = class
                lastKnownSpec[arenaIndex] = name
                lastKnownSpecTexture[arenaIndex] = icon
                lastKnownSpecID[arenaIndex] = id
                seenValidClassData[arenaIndex] = true
            end
        elseif not seenValidClassData[arenaIndex] then
            -- No spec data yet, but we have class data - store it as fallback
            lastKnownClass[arenaIndex] = currentClassFile
            seenValidClassData[arenaIndex] = true
        end
    end
end

-- ============================================================================
-- PUBLIC API - Get preserved class data
-- ============================================================================

-- Get the last known valid class for an arena unit
function MismatchHandler:GetKnownClass(arenaIndex)
    return lastKnownClass[arenaIndex]
end

-- Get the last known valid spec for an arena unit
function MismatchHandler:GetKnownSpec(arenaIndex)
    return lastKnownSpec[arenaIndex]
end

-- Get the last known valid spec texture for an arena unit
function MismatchHandler:GetKnownSpecTexture(arenaIndex)
    return lastKnownSpecTexture[arenaIndex]
end

-- Get the last known valid spec ID for an arena unit
function MismatchHandler:GetKnownSpecID(arenaIndex)
    return lastKnownSpecID[arenaIndex]
end

-- Check if we have valid class data for an arena unit
function MismatchHandler:HasValidClassData(arenaIndex)
    return seenValidClassData[arenaIndex] == true
end

-- Apply preserved class data to a frame
function MismatchHandler:ApplyPreservedClassData(frame, arenaIndex)
    if not frame then return end
    
    -- Only apply if we have valid data
    if seenValidClassData[arenaIndex] then
        -- Preserve existing class data if frame already has it
        if not frame.class or frame.class == "" then
            frame.class = lastKnownClass[arenaIndex]
        end
        
        if not frame.specID or frame.specID == 0 then
            frame.specID = lastKnownSpecID[arenaIndex]
        end
        
        if not frame.specIconTexture or frame.specIconTexture == "" then
            frame.specIconTexture = lastKnownSpecTexture[arenaIndex]
        end
    end
end

-- ============================================================================
-- ARENA_OPPONENT_UPDATE
-- ============================================================================

function MismatchHandler:ARENA_OPPONENT_UPDATE(event, unit, updateType)
    -- Only care in arena.
    if not IsActiveBattlefieldArena() then
        return
    end
    
    -- Validate unit.
    if not IsValidUnit(unit) then
        return
    end
    
    -- Extract arena index.
    local arenaIndex = tonumber(unit:match("arena(%d)"))
    if not arenaIndex then
        return
    end
    
    -- Update class data tracking BEFORE applying to frame
    UpdateClassDataTracking(arenaIndex, unit)
    
    -- This is kind of important I guess: create the frame if it doesn't exist yet.
    -- (Ex: stealth player finally shows up.)
    local frame = self:GetFrame(unit)
    if not frame then
        -- Try to get frame from FrameManager first.
        if AC.FrameManager then
            local frames = AC.FrameManager:GetFrames()
            if frames then
                if not frames[arenaIndex] then
                    -- Frame doesn't exist, create it.
                    if AC.FrameManager.CreateFrame then
                        AC.FrameManager:CreateFrame(arenaIndex)
                        frame = self:GetFrame(unit)
                    end
                end
            end
        end
        
        -- Still no frame.
        if not frame then
            return
        end
    end
    
    -- Get current spec data from API
    local specID = GetArenaOpponentSpec and GetArenaOpponentSpec(arenaIndex)
    
    -- KEY LOGIC: Only update frame data if API returns valid data
    -- Otherwise, preserve existing valid data (don't overwrite with 0 or nil)
    if specID and specID > 0 then
        local id, name, description, icon, role, class = GetSpecializationInfoByID(specID)
        if class then
            frame.class = class
            frame.specID = id
            frame.specIconTexture = icon
            
            -- Update our tracking
            lastKnownClass[arenaIndex] = class
            lastKnownSpec[arenaIndex] = name
            lastKnownSpecTexture[arenaIndex] = icon
            lastKnownSpecID[arenaIndex] = id
            seenValidClassData[arenaIndex] = true
        end
    else
        -- API returned invalid data (0 or nil)
        -- PRESERVE existing valid data instead of overwriting
        if seenValidClassData[arenaIndex] then
            -- We have valid stored data, use it
            if not frame.class or frame.class == "" then
                frame.class = lastKnownClass[arenaIndex]
            end
            if not frame.specID or frame.specID == 0 then
                frame.specID = lastKnownSpecID[arenaIndex]
            end
            if not frame.specIconTexture or frame.specIconTexture == "" then
                frame.specIconTexture = lastKnownSpecTexture[arenaIndex]
            end
        else
            -- No valid data yet, try to get class from UnitClass as fallback
            local _, classFile = UnitClass(unit)
            if classFile then
                frame.class = classFile
                lastKnownClass[arenaIndex] = classFile
                seenValidClassData[arenaIndex] = true
            end
        end
    end
    
    -- Update frame elements (moved from old handler).
    local AC = _G.ArenaCore
    if AC then
        -- Update dispels.
        if AC.UpdateDispelFrames then
            C_Timer.After(0.05, function()
                AC:UpdateDispelFrames()
            end)
        end
        
        -- Update trinkets and racials.
        if AC.TrinketsRacials and AC.TrinketsRacials.RefreshFrame then
            AC.TrinketsRacials:RefreshFrame(frame, unit)
        end
        
        -- Update MFM elements if available.
        local MFM = AC.MasterFrameManager
        if MFM then
            -- Update name (clear test mode names).
            if not AC.testModeEnabled and MFM.UpdateName then
                MFM:UpdateName(frame)
            end
            
            -- Update health and power.
            if MFM.UpdateHealth then MFM.UpdateHealth(frame) end
            if MFM.UpdatePower then MFM.UpdatePower(frame) end
        end
    end
    
    -- This is kind of important I guess: always show the frame.
    -- ArenaFrameStealth.lua handles alpha; we just make sure it's actually shown.
    self:ShowFrame(unit)
end

-- ============================================================================
-- ARENA_PREP_OPPONENT_SPECIALIZATIONS
-- ============================================================================

function MismatchHandler:ARENA_PREP_OPPONENT_SPECIALIZATIONS()
    -- We're now in prep room
    isInPrepRoom = true
    isInArenaMatch = false
    
    -- Clear seen valid data when entering prep room for a new match
    -- This ensures we don't carry over stale data from previous match
    wipe(seenValidClassData)
    wipe(seenArenaUnits)
    wipe(lastKnownClass)
    wipe(lastKnownSpec)
    wipe(lastKnownSpecTexture)
    wipe(lastKnownSpecID)
    
    -- Loop through actual opponent count.
    local numOpponents = GetNumArenaOpponentSpecs and GetNumArenaOpponentSpecs() or 0
    
    for i = 1, MAX_ARENA_ENEMIES do
        local unit = "arena" .. i
        local specID = GetArenaOpponentSpec and GetArenaOpponentSpec(i)
        
        if specID and specID > 0 then
            -- Get frame.
            local frame = self:GetFrame(unit)
            if frame then
                -- Update spec/class data.
                local id, name, description, icon, role, class = GetSpecializationInfoByID(specID)
                if class then
                    frame.class = class
                    frame.specID = id
                    frame.specIconTexture = icon
                    
                    -- Store in our tracking
                    lastKnownClass[i] = class
                    lastKnownSpec[i] = name
                    lastKnownSpecTexture[i] = icon
                    lastKnownSpecID[i] = id
                    seenValidClassData[i] = true
                end
                
                -- Show frame (alpha handled by ArenaFrameStealth.lua).
                self:ShowFrame(unit)
            end
        end
    end
    -- Don't explicitly hide extra frames.
    -- Only show frames with data and ignore the rest.
end

-- ============================================================================
-- PLAYER_ENTERING_WORLD
-- ============================================================================

function MismatchHandler:PLAYER_ENTERING_WORLD()
    -- Reset state when entering world
    ResetState()
end

-- ============================================================================
-- ZONE_CHANGED_NEW_AREA
-- ============================================================================

function MismatchHandler:ZONE_CHANGED_NEW_AREA()
    local _, instanceType = IsInInstance()
    
    if instanceType == "arena" then
        isInArenaMatch = true
        isInPrepRoom = false
    else
        -- Left arena
        ResetState()
    end
end

-- ============================================================================
-- FRAME MANAGEMENT
-- ============================================================================

function MismatchHandler:GetFrame(unit)
    -- Get frame from FrameManager.
    if not AC.FrameManager then
        return nil
    end
    
    local frames = AC.FrameManager:GetFrames()
    if not frames then
        return nil
    end
    
    -- Extract arena index.
    local arenaIndex = tonumber(unit:match("arena(%d)"))
    if not arenaIndex then
        return nil
    end
    
    local frame = frames[arenaIndex]
    return frame
end

function MismatchHandler:ShowFrame(unit)
    local frame = self:GetFrame(unit)
    if not frame then
        return
    end
    
    -- Don't interfere with combat lockdown.
    if InCombatLockdown() then
        return
    end
    
    -- Show the frame.
    frame:Show()
end

function MismatchHandler:HideFrame(unit)
    local frame = self:GetFrame(unit)
    if not frame then
        return
    end
    
    -- Don't interfere with combat lockdown.
    if InCombatLockdown() then
        return
    end
    
    -- Hide the frame.
    frame:Hide()
    frame:SetAlpha(0)
end

function MismatchHandler:UpdateAlpha(unit, alpha)
    local frame = self:GetFrame(unit)
    if not frame then
        return
    end
    
    -- Set alpha.
    frame:SetAlpha(alpha)
end

-- ============================================================================
-- UNIT_NAME_UPDATE
-- ============================================================================

function MismatchHandler:UNIT_NAME_UPDATE(event, unit)
    -- Only care in arena.
    if not IsActiveBattlefieldArena() then
        return
    end
    
    -- Validate unit.
    if not IsValidUnit(unit) then
        return
    end
    
    -- Extract arena index.
    local arenaIndex = tonumber(unit:match("arena(%d)"))
    if not arenaIndex then
        return
    end
    
    -- Update class data tracking
    UpdateClassDataTracking(arenaIndex, unit)
    
    -- Show the frame.
    self:ShowFrame(unit)
end

-- ============================================================================
-- EVENT REGISTRATION
-- ============================================================================

function MismatchHandler:RegisterEvents()
    -- Register arena events.
    eventFrame:RegisterEvent("ARENA_OPPONENT_UPDATE")
    eventFrame:RegisterEvent("ARENA_PREP_OPPONENT_SPECIALIZATIONS")
    eventFrame:RegisterEvent("UNIT_NAME_UPDATE")
    eventFrame:RegisterEvent("PLAYER_ENTERING_WORLD")
    eventFrame:RegisterEvent("ZONE_CHANGED_NEW_AREA")
    
    -- Set event handler.
    eventFrame:SetScript("OnEvent", function(self, event, ...)
        if event == "ARENA_OPPONENT_UPDATE" then
            MismatchHandler:ARENA_OPPONENT_UPDATE(event, ...)
        elseif event == "ARENA_PREP_OPPONENT_SPECIALIZATIONS" then
            MismatchHandler:ARENA_PREP_OPPONENT_SPECIALIZATIONS()
        elseif event == "UNIT_NAME_UPDATE" then
            MismatchHandler:UNIT_NAME_UPDATE(event, ...)
        elseif event == "PLAYER_ENTERING_WORLD" then
            MismatchHandler:PLAYER_ENTERING_WORLD()
        elseif event == "ZONE_CHANGED_NEW_AREA" then
            MismatchHandler:ZONE_CHANGED_NEW_AREA()
        end
    end)
end

function MismatchHandler:UnregisterEvents()
    eventFrame:UnregisterEvent("ARENA_OPPONENT_UPDATE")
    eventFrame:UnregisterEvent("ARENA_PREP_OPPONENT_SPECIALIZATIONS")
    eventFrame:UnregisterEvent("UNIT_NAME_UPDATE")
    eventFrame:UnregisterEvent("PLAYER_ENTERING_WORLD")
    eventFrame:UnregisterEvent("ZONE_CHANGED_NEW_AREA")
end

-- ============================================================================
-- INITIALIZATION
-- ============================================================================

function MismatchHandler:Initialize()
    -- Register events.
    self:RegisterEvents()
end

-- Auto-initialize.
C_Timer.After(0.1, function()
    if AC.MismatchHandler then
        AC.MismatchHandler:Initialize()
    end
end)

-- ============================================================================
-- DEBUG COMMANDS
-- ============================================================================

SLASH_ACMISMATCH1 = "/acmismatch"
SlashCmdList["ACMISMATCH"] = function(msg)
    if msg == "debug" then
        print("ArenaCore MismatchHandler Debug:")
        print("- Events registered: ARENA_OPPONENT_UPDATE, ARENA_PREP_OPPONENT_SPECIALIZATIONS, UNIT_NAME_UPDATE, PLAYER_ENTERING_WORLD, ZONE_CHANGED_NEW_AREA")
        print("- Frame count: " .. (AC.FrameManager and #AC.FrameManager:GetFrames() or 0))
        print("- In arena: " .. tostring(IsActiveBattlefieldArena()))
        print("- In match: " .. tostring(isInArenaMatch))
        print("- In prep room: " .. tostring(isInPrepRoom))
        
        local numOpps = GetNumArenaOpponentSpecs and GetNumArenaOpponentSpecs() or 0
        print("- Opponent count: " .. numOpps)
        
        for i = 1, MAX_ARENA_ENEMIES do
            local unit = "arena" .. i
            local frame = MismatchHandler:GetFrame(unit)
            if frame then
                local knownClass = MismatchHandler:GetKnownClass(i)
                local knownSpec = MismatchHandler:GetKnownSpec(i)
                local knownSpecID = MismatchHandler:GetKnownSpecID(i)
                local hasValidData = MismatchHandler:HasValidClassData(i)
                print(string.format("  - %s: visible=%s, alpha=%.1f, class=%s, spec=%s (%d), validData=%s", 
                    unit, tostring(frame:IsVisible()), frame:GetAlpha(), 
                    frame.class or "nil", knownSpec or "nil", knownSpecID or 0, tostring(hasValidData)))
            end
        end
    elseif msg == "reset" then
        ResetState()
        print("ArenaCore MismatchHandler: State reset")
    elseif msg == "clear" then
        -- Clear all frames
        for i = 1, MAX_ARENA_ENEMIES do
            local unit = "arena" .. i
            local frame = MismatchHandler:GetFrame(unit)
            if frame then
                frame.class = nil
                frame.specID = nil
                frame.specIconTexture = nil
            end
        end
        ResetState()
        print("ArenaCore MismatchHandler: All data cleared")
    else
        print("ArenaCore MismatchHandler")
        print("Usage: /acmismatch debug - Show debug information")
        print("       /acmismatch reset - Reset internal state")
        print("       /acmismatch clear - Clear all frame data and reset state")
    end
end
