--[[
============================================================================
ETB ClassRestrictions - Class restriction checking and alternative resolution
============================================================================
Uses compact data (position 23: cl field) for class restriction info.
WoW classIDs: 1=Warrior, 2=Paladin, 3=Hunter, 4=Rogue, 5=Priest,
              6=Death Knight, 7=Shaman, 8=Mage, 9=Warlock, 10=Monk, 11=Druid

Provides:
  - GetItemClassRestrictions(itemID) -> {classID, ...} or nil (nil = all classes)
  - IsItemUsableByClass(itemID, classID) -> bool
  - IsItemUsableByPlayer(itemID) -> bool
  - PickBestAlternative(alternatives, classID) -> item
============================================================================
]]--

local ADDON_NAME, NS = ...
local ETB = NS.ETB

ETB.ClassRestrictions = ETB.ClassRestrictions or {}
local CR = ETB.ClassRestrictions

-- Cache: itemID -> classIDs table or false (false = checked, no restriction)
CR.cache = {}
CR.cacheSize = 0
CR.maxCacheSize = 5000

-- =============================================================================
-- PLAYER CLASS
-- =============================================================================

local playerClassID = nil

function CR:GetPlayerClassID()
    if playerClassID then return playerClassID end
    
    -- Try from BlizzardData profile first
    if ETB.BlizzardData and ETB.BlizzardData.GetPlayerClassID then
        local cid = ETB.BlizzardData:GetPlayerClassID()
        if cid then playerClassID = cid; return cid end
    end
    
    -- Fallback: query WoW API
    local _, _, cid = UnitClass("player")
    if cid then playerClassID = cid end
    return playerClassID
end

-- =============================================================================
-- CORE: Get class restrictions for an item
-- =============================================================================

--- Get class restrictions for an item from compact data
-- @return table of classIDs, or nil (nil = usable by all)
function CR:GetItemClassRestrictions(itemID)
    if not itemID then return nil end
    
    -- Check cache
    local cached = self.cache[itemID]
    if cached ~= nil then
        return cached == false and nil or cached
    end
    
    local restrictions = nil
    
    -- Source 1: compact data via SourceData / MapperBridge
    if ETB.SourceData_ATT and ETB.SourceData_ATT.GetPrimarySource then
        local src = ETB.SourceData_ATT:GetPrimarySource(itemID)
        if src and src.classRestrictions and #src.classRestrictions > 0 then
            restrictions = src.classRestrictions
        end
    end
    
    -- Source 2: bitmask class data from ItemMetadata (11,702 items)
    if not restrictions and ETB.ClassRestrictionData then
        local bitmask = ETB.ClassRestrictionData[itemID]
        if bitmask and bitmask > 0 then
            restrictions = {}
            -- Decode bitmask: 1=War 2=Pal 4=Hun 8=Rog 16=Pri 32=DK 64=Sha 128=Mag 256=Lock 512=Monk 1024=Dru
            local CLASS_BITS = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024}
            for classID = 1, 11 do
                if bit.band(bitmask, CLASS_BITS[classID]) > 0 then
                    restrictions[#restrictions + 1] = classID
                end
            end
            if #restrictions == 0 or #restrictions == 11 then
                restrictions = nil  -- all classes = no restriction
            end
        end
    end
    
    -- Source 3: world-boss armor-type masks (Ordos / Timeless Isle, the Pandaria
    -- Celestials, Nalak, Oondasta, etc.). These retail-range items are absent
    -- from ItemMetadata, so without this they'd never filter by class/armor and
    -- the tooltip would show every armor type at once.
    if not restrictions and ETB.WorldBossArmorClass then
        local bitmask = ETB.WorldBossArmorClass[itemID]
        if bitmask and bitmask > 0 then
            restrictions = {}
            local CLASS_BITS = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024}
            for classID = 1, 11 do
                if bit.band(bitmask, CLASS_BITS[classID]) > 0 then
                    restrictions[#restrictions + 1] = classID
                end
            end
            if #restrictions == 0 or #restrictions == 11 then
                restrictions = nil
            end
        end
    end
    
    -- Cache result (false = no restriction found)
    if self.cacheSize < self.maxCacheSize then
        self.cache[itemID] = restrictions or false
        self.cacheSize = self.cacheSize + 1
    end
    
    return restrictions
end

--- Check if an item is usable by a specific class
-- @return true if usable (including "no restriction" items)
function CR:IsItemUsableByClass(itemID, classID)
    if not itemID or not classID then return true end
    
    local restrictions = self:GetItemClassRestrictions(itemID)
    if not restrictions then return true end -- No restriction = usable by all
    
    for _, allowedClassID in ipairs(restrictions) do
        if allowedClassID == classID then
            return true
        end
    end
    return false
end

--- Check if an item is usable by the current player
function CR:IsItemUsableByPlayer(itemID)
    local classID = self:GetPlayerClassID()
    if not classID then return true end -- Can't determine class, assume usable
    return self:IsItemUsableByClass(itemID, classID)
end

-- =============================================================================
-- ALTERNATIVE SELECTION: Pick the best item from a visualID group
-- =============================================================================

--- From a list of alternative items (same visualID), pick the best for the player
-- Priority: collected+usable > usable > collected > any
-- Within each tier: prefer higher quality, then non-restricted
function CR:PickBestAlternative(alternatives, classID)
    if not alternatives or #alternatives == 0 then return nil end
    if #alternatives == 1 then return alternatives[1] end
    
    classID = classID or self:GetPlayerClassID()
    
    -- Score each item
    local scored = {}
    for i, item in ipairs(alternatives) do
        local usable = true
        if classID and item.itemID then
            usable = self:IsItemUsableByClass(item.itemID, classID)
        end
        
        local score = 0
        if item.isCollected and usable then score = 300
        elseif usable then score = 200
        elseif item.isCollected then score = 100
        end
        
        -- Bonus for higher quality
        score = score + (tonumber(item.quality) or 0)
        
        -- Bonus for no class restriction (universal items preferred)
        local restrictions = item.itemID and self:GetItemClassRestrictions(item.itemID)
        if not restrictions then
            score = score + 10  -- Prefer unrestricted items
        end
        
        scored[i] = { item = item, score = score }
    end
    
    -- Sort by score descending
    table.sort(scored, function(a, b) return a.score > b.score end)
    
    return scored[1].item
end

--- Check if ANY item in a visualID group is usable by the player
-- Used to determine if an appearance should show at all under "My Class Only"
function CR:HasUsableAlternative(alternatives)
    if not alternatives then return false end
    local classID = self:GetPlayerClassID()
    if not classID then return true end
    
    for _, item in ipairs(alternatives) do
        if item.itemID then
            if self:IsItemUsableByClass(item.itemID, classID) then
                return true
            end
        else
            return true -- No itemID = can't check, assume usable
        end
    end
    return false
end

--- Format class restriction for display
-- @return string like "|cffff4444Priest, Mage only|r" or nil
function CR:FormatRestriction(itemID)
    local restrictions = self:GetItemClassRestrictions(itemID)
    if not restrictions then return nil end
    
    local CLASS_NAMES = {
        [1] = "Warrior", [2] = "Paladin", [3] = "Hunter", [4] = "Rogue",
        [5] = "Priest", [6] = "Death Knight", [7] = "Shaman", [8] = "Mage",
        [9] = "Warlock", [10] = "Monk", [11] = "Druid",
    }
    
    local names = {}
    for _, classID in ipairs(restrictions) do
        names[#names + 1] = CLASS_NAMES[classID] or ("Class " .. classID)
    end
    
    if #names == 0 then return nil end
    
    -- Check if player is in the list
    local playerClassID = self:GetPlayerClassID()
    local playerCanUse = false
    if playerClassID then
        for _, classID in ipairs(restrictions) do
            if classID == playerClassID then
                playerCanUse = true
                break
            end
        end
    end
    
    local color = playerCanUse and "|cffffff00" or "|cffff4444"
    return color .. table.concat(names, ", ") .. " only|r"
end

--- Clear cache (e.g., on character switch)
function CR:ClearCache()
    self.cache = {}
    self.cacheSize = 0
    playerClassID = nil
end

function CR:GetStats()
    return {
        cacheSize = self.cacheSize,
        playerClassID = self:GetPlayerClassID(),
    }
end

ETB:Debug("ClassRestrictions", "ClassRestrictions module loaded")
