--[[
============================================================================
ETB - WeaponData.lua
============================================================================
Specialized module for weapon data retrieval (Categories 12 & 13).
Handles Main Hand and Off Hand weapons with weapon-specific logic.

Key Features:
- Trusts Blizzard API completely (no validation)
- Lenient filtering (only filters if CERTAIN weapon is unusable)
- Handles two-handed vs one-handed detection
- Supports all weapon types (Sword, Axe, Mace, Dagger, etc.)
============================================================================
]]--

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

ETB.WeaponData = {
    cache = {
        categories = {},
        sources = {},
    },
    initialized = false,
}

local WD = ETB.WeaponData

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

function WD:Initialize()
    if self.initialized then return true end
    
    ETB:Debug("WeaponData", "Initializing WeaponData module...")
    
    -- Verify APIs
    if not C_TransmogCollection then
        ETB:PrintError("C_TransmogCollection not available!")
        return false
    end
    
    self.initialized = true
    ETB:Debug("WeaponData", "WeaponData module initialized")
    return true
end

-- =============================================================================
-- CORE API METHODS (Delegate to BlizzardData)
-- =============================================================================

function WD:GetCategoryAppearances(categoryID)
    -- Delegate to BlizzardData but add weapon-specific logging
    if not ETB.BlizzardData then return {} end
    
    local appearances = ETB.BlizzardData:GetCategoryAppearances(categoryID)
    
    -- Debug logging for weapons
    if #appearances == 0 then
        ETB:Debug("WeaponData", string.format("⚠️ No appearances found for weapon category %d", categoryID))
        -- Try to get categories from API to see what's available
        if C_TransmogCollection and C_TransmogCollection.GetCategories then
            local success, categories = pcall(C_TransmogCollection.GetCategories)
            if success and categories then
                ETB:Debug("WeaponData", string.format("Available categories: %d total", #categories))
                for _, cat in ipairs(categories) do
                    if cat and cat.categoryID then
                        ETB:Debug("WeaponData", string.format("  Category %d: %s", cat.categoryID, cat.name or "Unknown"))
                    end
                end
            end
        end
    else
        ETB:Debug("WeaponData", string.format("✅ Category %d: Found %d weapon appearances", categoryID, #appearances))
    end
    
    return appearances
end

function WD:GetAppearanceSources(visualID)
    if not ETB.BlizzardData then return {} end
    return ETB.BlizzardData:GetAppearanceSources(visualID)
end

-- =============================================================================
-- WEAPON-SPECIFIC ITEM RETRIEVAL
-- =============================================================================

-- Helper to check if category is a weapon category
function WD:IsWeaponCategory(categoryID)
    if not categoryID then return false end
    -- MoP Classic: Categories 12+ are weapon types
    local catInfo = ETB.CATEGORY_INFO and ETB.CATEGORY_INFO[categoryID]
    if catInfo and catInfo.isWeapon then
        return true
    end
    return categoryID >= 12
end

function WD:GetItemsForCategory(categoryID, options)
    -- Validate category ID - MoP Classic uses 12+ for weapons
    if not self:IsWeaponCategory(categoryID) then
        ETB:Debug("WeaponData", string.format("⚠️ GetItemsForCategory called with non-weapon category %d", categoryID))
        return {}
    end
    
    options = options or {}
    local limit = options.limit or 100000
    local onlyCollected = options.onlyCollected
    local onlyUncollected = options.onlyUncollected
    local onlyUsable = options.onlyUsable
    
    -- Get category info for better logging
    local catInfo = ETB.CATEGORY_INFO and ETB.CATEGORY_INFO[categoryID]
    local catName = catInfo and catInfo.name or ("Category " .. categoryID)
    
    ETB:Debug("WeaponData", string.format("Getting weapons for %s (cat %d, limit=%d, collected=%s, usable=%s)", 
        catName, categoryID, limit, tostring(onlyCollected), tostring(onlyUsable)))
    ETB:Debug("WeaponData", "NOTE: Loading ALL weapons regardless of class. Class filtering done in UI layer.")
    
    local items = {}
    local itemsByVisualID = {}
    local appearances = self:GetCategoryAppearances(categoryID)
    
    if #appearances == 0 then
        ETB:Print("|cffff0000[WeaponData]|r ERROR: No appearances found for weapon category %d!", categoryID)
        ETB:Print("|cffffff00[WeaponData]|r Try: /etbverify categories to see available categories")
        return {}
    end
    
    local totalSourcesProcessed = 0
    local totalSourcesSkipped = 0
    
    for _, appearance in ipairs(appearances) do
        if #items >= limit then break end
        
        -- Pre-filter by collection
        local skipAppearance = false
        if onlyCollected and not appearance.isCollected then
            skipAppearance = true
        elseif onlyUncollected and appearance.isCollected then
            skipAppearance = true
        end
        
        if not skipAppearance then
            -- For weapons, we're more lenient with isUsable
            -- Some weapons might show isUsable=false but still be usable
            local skipByUsability = false
            if onlyUsable and appearance.isUsable == false then
                -- Still check sources - might have usable variants
                skipByUsability = false  -- Don't skip, check sources instead
            end
            
            if not skipByUsability then
                local sources = self:GetAppearanceSources(appearance.visualID)
                totalSourcesProcessed = totalSourcesProcessed + #sources
                
                if #sources == 0 then
                    ETB:Debug("WeaponData", string.format("Warning: Appearance visualID %d has no sources", appearance.visualID))
                end
                
                for _, source in ipairs(sources) do
                    if #items >= limit then break end
                    
                    if not source.itemID then
                        ETB:Debug("WeaponData", string.format("Warning: Source missing itemID for visualID %d", appearance.visualID))
                        totalSourcesSkipped = totalSourcesSkipped + 1
                    else
                        -- Build item entry using BlizzardData
                        local item = ETB.BlizzardData:BuildItemEntry(source, appearance, categoryID)
                        
                        -- For weapons: NO VALIDATION - trust the API completely
                        -- The API knows which category each weapon belongs to
                        
                        -- IMPORTANT: Load ALL weapons regardless of class
                        -- Class filtering will be done in Filtering:ApplyFilters() as a UI-level filter
                        -- This ensures we have complete weapon data for all classes, then can filter/sort by class
                        local shouldInclude = true
                        
                        -- Only filter by class if explicitly requested AND onlyUsable is true
                        -- But for now, we load all weapons and filter in UI layer
                        -- This allows users to see all weapons and sort/filter by class later
                        if onlyUsable then
                            -- This should rarely be called now since Filtering sets onlyUsable=false for weapons
                            -- But keep the logic here as a fallback
                            if item.weaponType then
                                if not ETB.BlizzardData:CanPlayerUseWeaponType(item.weaponType) then
                                    shouldInclude = false
                                end
                            end
                            if shouldInclude and item.canWear == false and item.weaponType then
                                shouldInclude = false
                            end
                        end
                        
                        if shouldInclude then
                            local visualID = item.visualID or appearance.visualID
                            if not itemsByVisualID[visualID] then
                                itemsByVisualID[visualID] = { items = {}, selectedIndex = 1 }
                            end
                            table.insert(itemsByVisualID[visualID].items, item)
                        else
                            totalSourcesSkipped = totalSourcesSkipped + 1
                        end
                    end
                end
            end
        end
    end
    
    -- Debug logging
    local uniqueVisualCount = 0
    for _ in pairs(itemsByVisualID) do
        uniqueVisualCount = uniqueVisualCount + 1
    end
    ETB:Debug("WeaponData", string.format("Category %d: Processed %d sources, skipped %d, unique visuals: %d", 
        categoryID, totalSourcesProcessed, totalSourcesSkipped, uniqueVisualCount))
    
    -- Create unique items list (one per visualID)
    for visualID, data in pairs(itemsByVisualID) do
        if #items >= limit then break end
        
        -- Select best item (prefer collected, then highest quality, then first)
        local selectedItem = nil
        local bestIndex = 1
        
        -- Prefer collected items
        for i, item in ipairs(data.items) do
            if item.isCollected then
                selectedItem = item
                bestIndex = i
                break
            end
        end
        
        -- If no collected, prefer highest quality
        if not selectedItem then
            local bestQuality = -1
            for i, item in ipairs(data.items) do
                -- Ensure quality is a number (may come as string from API)
                local quality = item.quality
                if quality and type(quality) ~= "number" then
                    quality = tonumber(quality) or 0
                end
                if quality and quality > bestQuality then
                    bestQuality = quality
                    selectedItem = item
                    bestIndex = i
                end
            end
        end
        
        -- Fallback to first item
        if not selectedItem and #data.items > 0 then
            selectedItem = data.items[1]
            bestIndex = 1
        end
        
        if selectedItem then
            -- Store alternatives
            selectedItem.alternatives = data.items
            selectedItem.selectedAlternativeIndex = bestIndex
            selectedItem.hasAlternatives = #data.items > 1
            
            -- Queue for name loading AND weaponType detection. In low-memory
            -- mode, only hydrate the selected representative; alternatives
            -- resolve when the player opens/cycles the detail path.
            local hydrateAllAlternatives = not (ETB.IsLowMemoryMode and ETB:IsLowMemoryMode())
            for _, altItem in ipairs(data.items) do
                if hydrateAllAlternatives or altItem == selectedItem then
                    if altItem.itemID then
                        -- Request item info through the shared throttle.
                        if ETB.RequestItemInfoThrottled then
                            ETB:RequestItemInfoThrottled(altItem.itemID)
                        else
                            GetItemInfo(altItem.itemID)
                        end
                        if not altItem.name or altItem.name == "Loading..." then
                            ETB.BlizzardData.pendingItemInfo[altItem.itemID] = true
                        end
                    end
                end
            end
            
            items[#items + 1] = selectedItem
        end
    end
    
    ETB:Debug("WeaponData", string.format("✅ Category %d: Returning %d unique weapon items", categoryID, #items))
    
    return items
end

function WD:GetItemsForCategoryAsync(categoryID, options, callbacks)
    callbacks = callbacks or {}
    if not self:IsWeaponCategory(categoryID) then
        ETB:Debug("WeaponData", string.format("GetItemsForCategoryAsync called with non-weapon category %d", categoryID or 0))
        if callbacks.onComplete then callbacks.onComplete({}) end
        return
    end

    options = options or {}
    local limit = options.limit or 100000
    local onlyCollected = options.onlyCollected
    local onlyUncollected = options.onlyUncollected
    local onlyUsable = options.onlyUsable
    local appearances = self:GetCategoryAppearances(categoryID)
    if #appearances == 0 then
        if callbacks.onComplete then callbacks.onComplete({}) end
        return
    end

    local items = {}
    local itemsByVisualID = {}
    local totalSourcesProcessed = 0
    local totalSourcesSkipped = 0
    local appIndex = 1
    local currentAppearance, currentSources, sourceIndex
    local getTime = debugprofilestop or function() return 0 end
    local budgetMs = options.budgetMs or 3.0

    local function schedule(step)
        if ETB.QueueWork then
            ETB:QueueWork(nil, function() step(); return true end, { pauseInCombat = true, startupIdleOptions = { ignoreQuietWindow = true, pauseWhileMoving = false } })
        elseif C_Timer and C_Timer.After then
            C_Timer.After(0.01, step)
        else
            step()
        end
    end

    local function weaponTypeFromSubclass(subclassID)
        if subclassID == 0 then return "AXE", false
        elseif subclassID == 1 then return "AXE", true
        elseif subclassID == 2 then return "BOW", true
        elseif subclassID == 3 then return "GUN", false
        elseif subclassID == 4 then return "MACE", false
        elseif subclassID == 5 then return "MACE", true
        elseif subclassID == 6 then return "POLEARM", true
        elseif subclassID == 7 then return "SWORD", false
        elseif subclassID == 8 then return "SWORD", true
        elseif subclassID == 9 then return "WARGLAIVE", false
        elseif subclassID == 10 then return "STAFF", true
        elseif subclassID == 13 then return "FIST", false
        elseif subclassID == 15 then return "DAGGER", false
        elseif subclassID == 16 then return "THROWN", false
        elseif subclassID == 18 then return "CROSSBOW", true
        elseif subclassID == 19 then return "WAND", false
        end
        return nil, nil
    end

    local function processSource(appearance, source)
        if not source or not source.itemID then
            totalSourcesSkipped = totalSourcesSkipped + 1
            return
        end

        local _, _, _, equipLoc, itemIcon, classID, subclassID = GetItemInfoInstant(source.itemID)
        local weaponType, isTwoHanded = weaponTypeFromSubclass(subclassID)
        local cached = ETB.BlizzardData and ETB.BlizzardData.itemCache and ETB.BlizzardData.itemCache:Get(source.itemID)
        local item = cached or {
            itemID = source.itemID,
            sourceID = source.sourceID,
            visualID = appearance.visualID,
            appearanceID = appearance.appearanceID,
            name = "Loading...",
            quality = 2,
            icon = itemIcon or "Interface\\Icons\\INV_Misc_QuestionMark",
            isCollected = source.isCollected or appearance.isCollected,
            isUsable = appearance.isUsable,
            categoryID = categoryID,
            invType = equipLoc,
        }
        item.sourceID = item.sourceID or source.sourceID
        item.visualID = item.visualID or appearance.visualID
        item.appearanceID = item.appearanceID or appearance.appearanceID
        item.isCollected = source.isCollected or appearance.isCollected
        item.isUsable = appearance.isUsable
        item.categoryID = categoryID
        item.icon = item.icon or itemIcon or "Interface\\Icons\\INV_Misc_QuestionMark"
        item.invType = item.invType or equipLoc
        if weaponType then item.weaponType = weaponType end
        if isTwoHanded ~= nil then item.isTwoHanded = isTwoHanded end
        if (not item.name or item.name == "Loading..." or item.name == "Unknown") and ETB.RequestItemInfoThrottled then
            ETB:RequestItemInfoThrottled(source.itemID)
        end
        if ETB.BlizzardData and ETB.BlizzardData.itemCache and not cached then
            ETB.BlizzardData.itemCache:Set(source.itemID, item)
        end
        local shouldInclude = true
        if onlyUsable then
            if item.weaponType and not ETB.BlizzardData:CanPlayerUseWeaponType(item.weaponType) then
                shouldInclude = false
            end
            if shouldInclude and item.canWear == false and item.weaponType then
                shouldInclude = false
            end
        end

        if shouldInclude then
            local visualID = item.visualID or appearance.visualID
            if not itemsByVisualID[visualID] then
                itemsByVisualID[visualID] = { items = {}, selectedIndex = 1 }
            end
            table.insert(itemsByVisualID[visualID].items, item)
        else
            totalSourcesSkipped = totalSourcesSkipped + 1
        end
    end

    local function selectBest(data)
        local selectedItem, bestIndex
        for i, item in ipairs(data.items) do
            if item.isCollected then
                selectedItem = item
                bestIndex = i
                break
            end
        end
        if not selectedItem then
            local bestQuality = -1
            for i, item in ipairs(data.items) do
                local quality = item.quality
                if quality and type(quality) ~= "number" then
                    quality = tonumber(quality) or 0
                end
                if quality and quality > bestQuality then
                    bestQuality = quality
                    selectedItem = item
                    bestIndex = i
                end
            end
        end
        if not selectedItem and #data.items > 0 then
            selectedItem = data.items[1]
            bestIndex = 1
        end
        return selectedItem, bestIndex or 1
    end

    local function hydrateAlternatives(data, selectedItem)
        local hydrateAllAlternatives = not (ETB.IsLowMemoryMode and ETB:IsLowMemoryMode())
        for _, altItem in ipairs(data.items) do
            if hydrateAllAlternatives or altItem == selectedItem then
                if altItem.itemID then
                    if ETB.RequestItemInfoThrottled then
                        ETB:RequestItemInfoThrottled(altItem.itemID)
                    end
                    if not altItem.name or altItem.name == "Loading..." then
                        ETB.BlizzardData.pendingItemInfo[altItem.itemID] = true
                    end
                end
            end
        end
    end

    local function finish()
        local groupKeys = {}
        for visualID in pairs(itemsByVisualID) do
            groupKeys[#groupKeys + 1] = visualID
        end

        local groupIndex = 1
        local function groupStep()
            if callbacks.cancelled and callbacks.cancelled() then return end
            local started = getTime()
            while groupIndex <= #groupKeys and #items < limit do
                local data = itemsByVisualID[groupKeys[groupIndex]]
                groupIndex = groupIndex + 1
                local selectedItem, bestIndex = selectBest(data)
                if selectedItem then
                    selectedItem.alternatives = data.items
                    selectedItem.selectedAlternativeIndex = bestIndex
                    selectedItem.hasAlternatives = #data.items > 1
                    hydrateAlternatives(data, selectedItem)
                    items[#items + 1] = selectedItem
                end

                if (getTime() - started) >= budgetMs then
                    if callbacks.onProgress then callbacks.onProgress(groupIndex - 1, #groupKeys, "grouping") end
                    schedule(groupStep)
                    return
                end
            end

            ETB:Debug("WeaponData", string.format("Category %d async: processed %d sources, skipped %d, returned %d unique weapon items",
                categoryID, totalSourcesProcessed, totalSourcesSkipped, #items))
            if callbacks.onProgress then callbacks.onProgress(#groupKeys, #groupKeys, "complete") end
            if callbacks.onComplete then callbacks.onComplete(items, false) end
        end

        groupStep()
    end

    local function step()
        if callbacks.cancelled and callbacks.cancelled() then return end
        local started = getTime()

        while appIndex <= #appearances do
            if not currentAppearance then
                local appearance = appearances[appIndex]
                appIndex = appIndex + 1

                local skipAppearance = false
                if onlyCollected and not appearance.isCollected then
                    skipAppearance = true
                elseif onlyUncollected and appearance.isCollected then
                    skipAppearance = true
                end

                if not skipAppearance then
                    currentAppearance = appearance
                    currentSources = self:GetAppearanceSources(appearance.visualID)
                    totalSourcesProcessed = totalSourcesProcessed + #currentSources
                    sourceIndex = 1
                end
            end

            while currentAppearance and sourceIndex <= #currentSources do
                processSource(currentAppearance, currentSources[sourceIndex])
                sourceIndex = sourceIndex + 1

                if (getTime() - started) >= budgetMs then
                    if callbacks.onProgress then callbacks.onProgress(appIndex - 1, #appearances, "building") end
                    schedule(step)
                    return
                end
            end

            currentAppearance = nil
            currentSources = nil
            sourceIndex = nil

            if (getTime() - started) >= budgetMs then
                if callbacks.onProgress then callbacks.onProgress(appIndex - 1, #appearances, "building") end
                schedule(step)
                return
            end
        end

        finish()
    end

    step()
end

-- =============================================================================
-- WEAPON-SPECIFIC STATISTICS
-- =============================================================================

function WD:GetCollectionStats(categoryID)
    if not ETB.BlizzardData then
        return { total = 0, collected = 0, usable = 0, percent = 0 }
    end
    return ETB.BlizzardData:GetCollectionStats(categoryID)
end

-- =============================================================================
-- CACHE MANAGEMENT
-- =============================================================================

function WD:InvalidateCache()
    wipe(self.cache.categories)
    wipe(self.cache.sources)
    ETB:Debug("WeaponData", "Weapon cache invalidated")
end

ETB:Debug("WeaponData", "WeaponData.lua loaded")
