# ============================================================
# Nginx Lua Caching Configuration
# ============================================================
#
# 功能说明:
# - 使用 Lua 共享字典缓存响应
# - 支持 TTL 过期和手动失效
# - X-Cache 头标识缓存命中状态
#
# 使用方式:
#   lua_shared_dict response_cache 10m;
#   content_by_lua_file /path/to/cache_handler.lua;
# ============================================================

http {
    # 共享字典定义
    lua_shared_dict response_cache 10m;

    # 初始化 Lua 模块路径
    lua_package_path "/path/to/lua/?.lua;;";

    init_by_lua_block {
        -- 全局配置
        CACHE_DEFAULT_TTL = 60
    }

    server {
        listen 80;
        server_name cache.example.com;

        # ---------- 缓存读取示例 ----------
        location /api/data {
            set $cache_key "api_data:$request_uri";

            content_by_lua_block {
                local handler = require "cache_handler"
                local cache = ngx.shared.response_cache

                local key = ngx.var.cache_key
                local ttl = tonumber(ngx.var.arg_ttl) or CACHE_DEFAULT_TTL

                -- 尝试缓存命中
                local cached = cache:get(key)
                if cached then
                    ngx.header["X-Cache"] = "HIT"
                    ngx.header["Content-Type"] = "application/json"
                    ngx.header["X-Cache-TTL"] = tostring(cache:ttl(key))
                    ngx.say(cached)
                    return
                end

                -- 缓存未命中，生成数据
                local data = {
                    message = "fresh data",
                    timestamp = ngx.now(),
                    uri = ngx.var.request_uri,
                }

                local cjson = require "cjson.safe"
                local json = cjson.encode(data)

                -- 写入缓存
                local ok, err, forcible = cache:set(key, json, ttl)
                if not ok then
                    ngx.log(ngx.ERR, "cache set failed: ", err)
                end
                if forcible then
                    ngx.log(ngx.WARN, "cache LRU eviction triggered")
                end

                ngx.header["X-Cache"] = "MISS"
                ngx.header["Content-Type"] = "application/json"
                ngx.say(json)
            }
        }

        # ---------- 使用外部 Lua 文件 ----------
        location /api/handler {
            set $cache_key "handler:$request_uri";
            set $cache_ttl 120;

            content_by_lua_file /path/to/lua/cache_handler.lua;
        }

        # ---------- 缓存失效：清除指定 key ----------
        location /cache/purge {
            content_by_lua_block {
                if ngx.req.get_method() ~= "POST" then
                    ngx.status = 405
                    ngx.say('{"error": "method not allowed"}')
                    return
                end

                ngx.req.read_body()
                local body = ngx.req.get_body_data()
                if not body then
                    ngx.status = 400
                    ngx.say('{"error": "missing request body"}')
                    return
                end

                local cjson = require "cjson.safe"
                local data = cjson.decode(body)
                if not data or not data.key then
                    ngx.status = 400
                    ngx.say('{"error": "missing key field"}')
                    return
                end

                local cache = ngx.shared.response_cache
                cache:delete(data.key)

                ngx.header["Content-Type"] = "application/json"
                ngx.say(cjson.encode({success = true, purged = data.key}))
            }
        }

        # ---------- 缓存失效：清除全部 ----------
        location /cache/purge_all {
            # 仅允许本地访问
            allow 127.0.0.1;
            deny all;

            content_by_lua_block {
                if ngx.req.get_method() ~= "POST" then
                    ngx.status = 405
                    ngx.say('{"error": "method not allowed"}')
                    return
                end

                local cache = ngx.shared.response_cache
                local count = cache:flush_all()
                -- flush_all 标记所有 key 过期，flush_expired 实际清理
                cache:flush_expired(0)

                ngx.header["Content-Type"] = "application/json"
                ngx.say('{"success": true, "action": "all keys invalidated"}')
            }
        }

        # ---------- 缓存统计 ----------
        location /cache/stats {
            content_by_lua_block {
                local cache = ngx.shared.response_cache
                local keys = cache:get_keys(0)  -- 0 = 不过滤过期 key
                local cjson = require "cjson.safe"

                local stats = {
                    capacity = cache:capacity(),
                    free_space = cache:free_space(),
                    key_count = #keys,
                }

                ngx.header["Content-Type"] = "application/json"
                ngx.say(cjson.encode(stats))
            }
        }
    }
}
