--[[
============================================================================
ETB v10.0 - LRUCache.lua
============================================================================
Bounded LRU (Least Recently Used) cache implementation.
Prevents unbounded memory growth by evicting oldest entries.
============================================================================
]]--

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

-- LRUCache class
local LRUCache = {}
LRUCache.__index = LRUCache

function LRUCache:New(maxSize, name)
    local cache = setmetatable({}, LRUCache)
    cache.maxSize = maxSize or 500
    cache.name = name or "LRUCache"
    cache.data = {}
    cache.order = {}  -- Array of keys in order of use (oldest first)
    cache.size = 0
    cache.hits = 0
    cache.misses = 0
    return cache
end

function LRUCache:Get(key)
    local value = self.data[key]
    if value ~= nil then
        self.hits = self.hits + 1
        self:_touch(key)
        return value
    end
    self.misses = self.misses + 1
    return nil
end

function LRUCache:Set(key, value)
    if self.data[key] ~= nil then
        -- Update existing
        self.data[key] = value
        self:_touch(key)
    else
        -- Add new
        if self.size >= self.maxSize then
            self:_evictOldest()
        end
        self.data[key] = value
        table.insert(self.order, key)
        self.size = self.size + 1
    end
end

function LRUCache:Has(key)
    return self.data[key] ~= nil
end

function LRUCache:Remove(key)
    if self.data[key] ~= nil then
        self.data[key] = nil
        for i, k in ipairs(self.order) do
            if k == key then
                table.remove(self.order, i)
                break
            end
        end
        self.size = self.size - 1
        return true
    end
    return false
end

function LRUCache:Clear()
    wipe(self.data)
    wipe(self.order)
    self.size = 0
end

function LRUCache:_touch(key)
    -- Move key to end (most recently used)
    for i, k in ipairs(self.order) do
        if k == key then
            table.remove(self.order, i)
            break
        end
    end
    table.insert(self.order, key)
end

function LRUCache:_evictOldest()
    if self.size > 0 then
        local oldestKey = table.remove(self.order, 1)
        if oldestKey then
            self.data[oldestKey] = nil
            self.size = self.size - 1
        end
    end
end

function LRUCache:GetStats()
    return {
        name = self.name,
        size = self.size,
        maxSize = self.maxSize,
        hits = self.hits,
        misses = self.misses,
        hitRate = self.hits + self.misses > 0 and 
                  (self.hits / (self.hits + self.misses) * 100) or 0,
    }
end

-- Export
ETB.LRUCache = LRUCache

-- Factory function
function ETB:CreateLRUCache(maxSize, name)
    return LRUCache:New(maxSize, name)
end
