local ngx = ngx
local cjson = require "cjson"
local cache_utils = require "sm.utils.cache_utils"
local cache_stats = ngx.shared["cache_stats"]
local cache_meta = ngx.shared["cache_meta"]

local _M = {}

-- 缓存配置
local CACHE_CONFIG = {
    max_size = 20 * 1024 * 1024 * 1024, -- 20GB
    cleanup_threshold = 0.9, -- 当使用率达到90%时触发清理
    cleanup_ratio = 0.2, -- 每次清理20%的缓存
    min_ttl = 60, -- 最小缓存时间（秒）
    max_ttl = 30 * 24 * 60 * 60, -- 最大缓存时间（秒）
    extra_ttl = 60, -- 缓存key额外存在时间（秒）
    check_interval = 60, -- 检查间隔（秒）
    monitor_interval = 60, -- 监控统计间隔（秒）
    warmup_batch_size = 100, -- 每次预热处理的URL数量
    warmup_concurrency = 5 -- 预热并发数
}

-- 初始化缓存系统
-- @return boolean ok 是否成功
-- @return string|nil err 错误信息
function _M.init()
    ngx.log(ngx.INFO, "[Init] Initializing Cache")

    -- 检查共享字典是否可用
    if not cache_meta then
        ngx.log(ngx.ERR, "[Init] cache_meta shared dict not found")
        return nil, "cache_meta shared dict not found"
    end

    if not cache_stats then
        ngx.log(ngx.ERR, "[Init] cache_stats shared dict not found")
        return nil, "cache_stats shared dict not found"
    end

    -- 启动定期清理任务
    if ngx.worker.id() == 0 then
        -- 定期清理过期缓存
        ngx.timer.every(CACHE_CONFIG.check_interval, function()
            _M.cleanup_expired_cache()
        end)

        -- 定期记录缓存统计信息
        ngx.timer.every(CACHE_CONFIG.monitor_interval, function()
            local stats = _M.get_stats()
            ngx.log(ngx.INFO, "Cache stats: " .. cjson.encode(stats))
        end)
    end

    return true
end

-- 更新缓存统计信息
-- @param string cache_key 缓存键
-- @param string file_path 缓存文件路径
-- @param number ttl 缓存过期时间
-- @param boolean hit 是否命中
local function update_cache_stats(cache_key, file_path, ttl, hit)
    local size = cache_utils.get_file_size(file_path)
    local now = ngx.time()

    -- 更新访问统计
    local stats = cache_stats:get("cache_stats:" .. cache_key) or {
        access_count = 0,
        hit_count = 0,
        miss_count = 0,
        last_access = 0,
        size = 0,
        ttl = ttl,
        created_at = now
    }

    stats.last_access = now
    stats.access_count = stats.access_count + 1
    stats.size = size

    if hit then
        stats.hit_count = stats.hit_count + 1
    else
        stats.miss_count = stats.miss_count + 1
    end

    -- 使用shared dict存储统计信息
    cache_stats:set("cache_stats:" .. cache_key, stats)

    -- 更新全局统计
    local global_stats = cache_stats:get("global_cache_stats") or {
        total_size = 0,
        file_count = 0,
        hit_count = 0,
        miss_count = 0,
        last_update = 0
    }

    global_stats.total_size = global_stats.total_size + (size - stats.size)
    global_stats.hit_count = global_stats.hit_count + (hit and 1 or 0)
    global_stats.miss_count = global_stats.miss_count + (hit and 0 or 1)
    global_stats.last_update = now

    cache_stats:set("global_cache_stats", global_stats)
end

-- 清理过期缓存
function _M.cleanup_expired_cache()
    ngx.log(ngx.INFO, "Starting cache cleanup")
    local now = ngx.time()
    local total_size = 0
    local files_to_clean = {}

    -- 获取所有缓存key
    local keys = cache_meta:get_keys(0) -- 0 表示获取所有key
    if not keys then
        ngx.log(ngx.ERR, "Failed to get cache keys")
        return
    end

    for _, full_key in ipairs(keys) do
        -- ngx.log(ngx.INFO, "Processing key: " .. full_key)
        -- 只处理缓存元数据key
        local meta_str = cache_meta:get(full_key)
        ngx.log(ngx.INFO, "Meta data: " .. meta_str)
        if meta_str then
            local meta = cjson.decode(meta_str)
            if meta and meta.path and meta.ttl and meta.created_at then
                if cache_utils.check_cache_file(meta.path) then
                    ngx.log(ngx.INFO, "Checking file: ".. meta.path)
                    -- 检查是否过期
                    if now - meta.created_at > tonumber(meta.ttl) then
                        table.insert(files_to_clean, {
                            path = meta.path,
                            key = full_key,
                            last_access = meta.last_access or 0,
                            size = meta.size
                        })
                    else
                        total_size = total_size + meta.size
                    end
                else
                    -- 文件不存在，清理元数据
                    cache_meta:delete(full_key)
                end
            else
                -- 元数据不完整，清理
                cache_meta:delete(full_key)
            end
        end
    end

    -- 如果总大小超过阈值，清理最旧的缓存
    if total_size > CACHE_CONFIG.max_size * CACHE_CONFIG.cleanup_threshold then
        -- todo
    end
    for _, file in ipairs(files_to_clean) do
        os.remove(file.path)
        cache_meta:delete("cache_meta:" .. file.key)
        ngx.log(ngx.INFO, "delete up cache file: ".. file.path .. " ,key: ".. file.key.. ")")
    end
end

-- 获取缓存统计信息
function _M.get_stats()
    local stats = cache_stats:get("global_cache_stats") or {
        total_size = 0,
        file_count = 0,
        hit_count = 0,
        miss_count = 0,
        last_update = 0
    }

    -- 计算命中率
    local total_requests = stats.hit_count + stats.miss_count
    stats.hit_ratio = total_requests > 0 and (stats.hit_count / total_requests) or 0

    -- 计算存储使用率
    stats.storage_ratio = stats.total_size / CACHE_CONFIG.max_size

    return stats
end

-- 处理缓存
-- @param string cache_key 缓存键
-- @param number ttl 缓存过期时间
-- @return boolean hit 是否命中缓存
-- @return string|nil content 缓存内容
function _M.handle_cache(cache_key, ttl)
    ngx.log(ngx.INFO, "Handling cache for key: " .. ttl)
    local file_path = cache_utils.get_cache_file_path(cache_key)
    -- 检查缓存文件
    if cache_utils.check_cache_file(file_path) then
        -- 缓存命中，读取并返回内容
        local content = cache_utils.read_cache_file(file_path)
        if content then
            -- 查询是否在cache_meta中缓存，防止重启后缓存失效
            local meta = cache_meta:get(cache_key)
            if not meta then
                -- 更新缓存元数据
                local meta = {
                    key = cache_key,
                    path = file_path,
                    size = #content,
                    ttl = ttl,
                    created_at = ngx.time()
                }
                cache_meta:set(cache_key, cjson.encode(meta), tonumber(ttl) + CACHE_CONFIG.extra_ttl)
            end
            -- 更新访问统计
            update_cache_stats(cache_key, file_path, ttl, true)
            return true, content
        end
    end
    return false, nil
end

-- 保存响应到缓存
-- @param string cache_key 缓存键
-- @param number ttl 缓存过期时间
-- @param number size 缓存大小
-- @return boolean ok 是否成功
-- @return string|nil err 错误信息
function _M.save_response(cache_key, ttl, size)
    ngx.log(ngx.INFO, "Cache saved: " .. cache_key .. " ,ttl: " .. ttl)
    local file_path = cache_utils.get_cache_file_path(cache_key)
    -- 更新缓存元数据
    local meta = {
        key = cache_key,
        path = file_path,
        size = size,
        ttl = ttl,
        created_at = ngx.time()
    }
    cache_meta:set(cache_key, cjson.encode(meta), tonumber(ttl) + CACHE_CONFIG.extra_ttl)

    -- 更新统计信息
    update_cache_stats(cache_key, file_path, ttl, false)

    return true
end

-- 删除缓存
-- @param string cache_key 缓存键
-- @return boolean ok 是否成功
-- @return string|nil err 错误信息
function _M.delete_cache(cache_key)
    local file_path = cache_utils.get_cache_file_path(cache_key)

    -- 删除缓存文件
    local ok, err = os.remove(file_path)
    if not ok then
        return false, err
    end

    -- 删除元数据
    cache_meta:delete("cache_meta:" .. cache_key)

    return true
end

return _M
