-- data.lua
-- Pre-baked static indexes for instant, lag-free search
-- New Two-Stage Normalization Format

---@diagnostic disable: undefined-global
local ITEM_NAMES_LIST = ITEM_NAMES_LIST
local VENDOR_INDEX_LIST = VENDOR_INDEX_LIST
local ITEMLOCATIONSLIST = ITEMLOCATIONSLIST
local WDIGI_SOURCE_LOOKUP = WDIGI_SOURCE_LOOKUP

local ADDON_NAME, WDIGI = ...
WDIGI.Data = WDIGI.Data or {}

-- Control Characters
local RS = string.char(30) -- Record Separator (\x1e)
local US = string.char(31) -- Unit Separator (\x1f)

------------------------------------------------------------
-- VENDOR TYPE ENUM
------------------------------------------------------------
WDIGI.Data.VENDOR_TYPE = {
    SOLD_BY           = 1,
    DROPPED_BY        = 2,
    CONTAINED_IN      = 3,
    DISENCHANTED_FROM = 4,
    GATHERED_FROM     = 5,
    CRAFTED_BY        = 6,
    LEARNED_FROM      = 7,
    QUEST_REWARD      = 8,
    UNKNOWN           = 99,
}

------------------------------------------------------------
-- CACHE & STATE
------------------------------------------------------------
WDIGI.Data.Parsed = {}

------------------------------------------------------------
-- MONEY FORMATTER
------------------------------------------------------------
local function FormatMoney(copper)
    local amt = tonumber(copper) or 0
    if amt <= 0 then return "" end 

    local g = math.floor(amt / 10000)
    local s = math.floor((amt % 10000) / 100)
    local c = amt % 100

    local res = ""
    if g > 0 then res = res .. g .. "|cffffd700g|r " end
    if s > 0 then res = res .. s .. "|cffc7c7cfs|r " end
    if c > 0 or res == "" then res = res .. c .. "|cffeda55fc|r" end

    return res:trim()
end

------------------------------------------------------------
-- INTERNAL: Parse raw ITEMLOCATIONSLIST (The Inflator)
------------------------------------------------------------
local function ParseItemData(itemID)
    if WDIGI.Data.Parsed[itemID] then return WDIGI.Data.Parsed[itemID] end

    -- Use the global if it exists, otherwise a fallback empty table
    local itemsList = _G["ITEMLOCATIONSLIST"]
    local sourceLookup = _G["WDIGI_SOURCE_LOOKUP"]
    
    local raw = itemsList and itemsList[itemID]
    if type(raw) ~= "string" or raw == "" then return {} end

    local entries = {}
    local records = { strsplit(RS, raw) }

    for _, record in ipairs(records) do
        if record ~= "" then
            local sid, costVal, ver, dType, sID, sType = strsplit(US, record)
            
            -- Look up the NPC/Source data
            local sourceRaw = sourceLookup and sourceLookup[tonumber(sid)]
            if sourceRaw then
                local name, uMap, pMap, x, y = strsplit(US, sourceRaw)
                table.insert(entries, {
                    vendorName   = name or "Unknown",
                    mapID        = tonumber(uMap) or 0,
                    parentMapID  = tonumber(pMap) or 0,
                    tx           = tonumber(x) or 0,
                    ty           = tonumber(y) or 0,
                    cost         = costVal,
                    vendorType   = tonumber(dType) or 99,
                    npcID        = tonumber(sID) or 0,
                    sourceType   = sType or "",
                    clientVer    = ver or ""
                })
            end
        end
    end

    WDIGI.Data.Parsed[itemID] = entries
    return entries
end

------------------------------------------------------------
-- PUBLIC: Best location for navigation
------------------------------------------------------------
function WDIGI.Data.GetBestLocation(itemID)
    local entries = ParseItemData(itemID)
    if not entries or #entries == 0 then return nil end

    local myMapID, px, py = WDIGI.MapUtils.GetCurrentPlayerData()
    
    -- Fallback to first entry if player location is unknown
    if not myMapID or not px or not py then
        local e = entries[1] 
        return {
            vendorName = e.vendorName,
            zoneID     = e.mapID, -- consistent naming
            x          = e.tx,
            y          = e.ty,
            cost       = e.cost,
            vendorType = e.vendorType,
        }
    end

    local bestEntry, bestDist

    for _, e in ipairs(entries) do
        if e.mapID > 0 and e.tx > 0 then
            local onMap = WDIGI.MapUtils.IsSameZone(myMapID, e.mapID)

            if onMap then
                local dx = (e.tx / 100) - px
                local dy = (e.ty / 100) - py
                local dist = math.sqrt(dx * dx + dy * dy) * (WDIGI.MapUtils.GetZoneMultiplier() or 1000)

                if not bestDist or dist < bestDist then
                    bestDist  = dist
                    bestEntry = e
                end
            end
        end
    end

    local chosen = bestEntry or entries[1]
    return {
        vendorName = chosen.vendorName,
        zoneID     = chosen.mapID,
        x          = chosen.tx,
        y          = chosen.ty,
        cost       = chosen.cost,
        vendorType = chosen.vendorType,
    }
end

------------------------------------------------------------
-- PUBLIC: Universal Search Engine
------------------------------------------------------------
function WDIGI.Data.UniversalSearch(query)
    if not query or query == "" then return { items = {}, areas = {}, creatures = {} } end
    query = query:lower():trim()
    
    local results = { items = {}, areas = {}, creatures = {} }
    local seenVendors = {}

    local vendorIndex = _G["VENDOR_INDEX_LIST"]
    if vendorIndex then
        for vendorName, itemIds in pairs(vendorIndex) do
            if vendorName:find(query, 1, true) then
                if not seenVendors[vendorName] then
                    -- Return a simple string list
                    table.insert(results.creatures, vendorName)
                    seenVendors[vendorName] = true
                end
            end
            if #results.creatures >= 50 then break end
        end
    end
    
    -- 4. Search for ITEMS (Right Column)
    local namesList = _G["ITEM_NAMES_LIST"]
    if namesList then
        for id, name in pairs(namesList) do
            if name:lower():find(query, 1, true) then
                table.insert(results.items, id)
                if #results.items >= 60 then break end
            end
        end
    end

    return results
end

function WDIGI.Data.GetItemsByVendorName(vendorName)
    -- Normalize the name to match our lowercase index keys
    local key = vendorName:lower():trim()
    return VENDOR_INDEX_LIST and VENDOR_INDEX_LIST[key] or {}
end

------------------------------------------------------------
-- PUBLIC: Group by Item Source 
------------------------------------------------------------
function WDIGI.Data.GetGroupedSources(itemID)
    local sources = ParseItemData(itemID)
    local grouped = {}
    
    for _, s in ipairs(sources) do
        local mapInfo = C_Map.GetMapInfo(s.mapID)
        local zoneName = mapInfo and mapInfo.name or "Unknown Location"
        
        if not grouped[zoneName] then
            grouped[zoneName] = { 
                name = zoneName, 
                mapID = s.mapID, 
                entries = {} 
            }
        end
        table.insert(grouped[zoneName].entries, s)
    end
    
    return grouped
end

------------------------------------------------------------
-- EXPORTS
------------------------------------------------------------
WDIGI.Data.ParseItemData = ParseItemData
WDIGI.Data.FormatMoney   = FormatMoney