local http = require("resty.http")
local ngx = {
    var = {},
    shared = {
        o11y_route_data = {
            get = function() end,
            set = function() end
        }
    },
    escape_uri = function() end,
    log = function() end,
    ERR = "ERR",
    INFO = "INFO",
    HTTP_BAD_REQUEST = 400,
    HTTP_INTERNAL_SERVER_ERROR = 500,
    status = nil,
    exit = function() end,
    req = {
        set_uri = function() end
    }
}

local dynamic_route = require("dynamic_route")

describe("dynamic_route", function()
    local original_ngx

    before_each(function()
        original_ngx = _G.ngx
        _G.ngx = ngx
        package.loaded["dynamic_route"] = nil
        dynamic_route = require("dynamic_route")
    end)

    after_each(function()
        _G.ngx = original_ngx
    end)

    describe("rewrite_url", function()
        it("should rewrite the URL if cache hit for original path type", function()
            ngx.var = { uri = "/test", [1] = "devtier", [2] = "tenant", [3] = "project", [4] = "application", [5] = "api/v1/query" }
            stub(ngx.shared.o11y_route_data, "get").returns('{"vmTenant": "123:456", "code": 200}')
            stub(ngx.req, "set_uri")
            dynamic_route.rewrite_url("original")
            assert.stub(ngx.shared.o11y_route_data.get).was_called_with(ngx.shared.o11y_route_data, "devtiertenantprojectapplication")
            assert.stub(ngx.req.set_uri).was_called_with("/select/123:456/prometheus/api/v1/query", false)
            ngx.shared.o11y_route_data.get:revert()
            ngx.req.set_uri:revert()
        end)

        it("should rewrite the URL if cache hit for ignoreProject path type", function()
            ngx.var = { uri = "/test", [1] = "devtier", [2] = "tenant", [3] = "application", [4] = "api/v1/query" }
            stub(ngx.shared.o11y_route_data, "get").returns('{"vmTenant": "123:456", "code": 200}')
            stub(ngx.req, "set_uri")
            dynamic_route.rewrite_url("ignoreProject")
            assert.stub(ngx.shared.o11y_route_data.get).was_called_with(ngx.shared.o11y_route_data, "devtiertenantapplication")
            assert.stub(ngx.req.set_uri).was_called_with("/select/123:456/prometheus/api/v1/query", false)
            ngx.shared.o11y_route_data.get:revert()
            ngx.req.set_uri:revert()
        end)

        it("should rewrite the URL if cache hit for useO11yID path type", function()
            ngx.var = { uri = "/test", [1] = "metrics", [2] = "api/v1/query" }
            stub(ngx.shared.o11y_route_data, "get").returns('{"vmTenant": "123:456", "code": 200}')
            stub(ngx.req, "set_uri")
            dynamic_route.rewrite_url("useO11yID")
            assert.stub(ngx.shared.o11y_route_data.get).was_called_with(ngx.shared.o11y_route_data, "metrics")
            assert.stub(ngx.req.set_uri).was_called_with("/select/123:456/prometheus/api/v1/query", false)
            ngx.shared.o11y_route_data.get:revert()
            ngx.req.set_uri:revert()
        end)

        it("should fetch origin and set cache if cache miss for ignoreProject", function()
            ngx.var = { uri = "/test", [1] = "devtier", [2] = "tenant", [3] = "application", [4] = "api/v1/query" }
            stub(ngx.shared.o11y_route_data, "get").returns(nil)
            stub(http, "new").returns({
                request_uri = function()
                    return { status = 200, body = '{"data": {"vmAccountID": "123", "vmProjectID": "456"}}' }
                end
            })
            stub(ngx, "escape_uri").returns("/tenant/application/api/v1/query")
            stub(ngx.shared.o11y_route_data, "set")
            stub(ngx.req, "set_uri")
            dynamic_route.rewrite_url("ignoreProject")
            assert.stub(ngx.shared.o11y_route_data.set).was_called_with(ngx.shared.o11y_route_data, "devtiertenantapplication", '{"code":200,"vmTenant":"123:456"}', 3600)
            assert.stub(ngx.req.set_uri).was_called_with("/select/123:456/prometheus/api/v1/query", false)

            ngx.shared.o11y_route_data.get:revert()
            ngx.shared.o11y_route_data.set:revert()
            ngx.req.set_uri:revert()
            ngx.escape_uri:revert()
            http.new:revert()
        end)

        it("should fetch origin and set cache if cache miss for useO11yID", function()
            ngx.var = { uri = "/test", [1] = "metrics", [2] = "api/v1/query" }
            stub(ngx.shared.o11y_route_data, "get").returns(nil)
            stub(http, "new").returns({
                request_uri = function()
                    return { status = 200, body = '{"data": {"vmAccountID": "123", "vmProjectID": "456"}}' }
                end
            })
            stub(ngx, "escape_uri").returns("/metrics/api/v1/query")
            stub(ngx.shared.o11y_route_data, "set")
            stub(ngx.req, "set_uri")
            dynamic_route.rewrite_url("useO11yID")
            assert.stub(ngx.shared.o11y_route_data.set).was_called_with(ngx.shared.o11y_route_data, "metrics", '{"code":200,"vmTenant":"123:456"}', 3600)
            assert.stub(ngx.req.set_uri).was_called_with("/select/123:456/prometheus/api/v1/query", false)

            ngx.shared.o11y_route_data.get:revert()
            ngx.shared.o11y_route_data.set:revert()
            ngx.req.set_uri:revert()
            ngx.escape_uri:revert()
            http.new:revert()
        end)

        it("should return error if fetch_origin fails for useO11yID", function()
            ngx.var = { uri = "/test", [1] = "metrics", [2] = "api/v1/query" }
            stub(ngx.shared.o11y_route_data, "get").returns(nil)
            stub(http, "new").returns({
                request_uri = function() return { status = 404 } end
            })
            stub(ngx, "escape_uri").returns("/metrics/api/v1/query")
            stub(ngx, "exit")

            dynamic_route.rewrite_url("useO11yID")
            assert.stub(ngx.exit).was_called_with(404)
            http.new:revert()
            ngx.escape_uri:revert()
            ngx.shared.o11y_route_data.get:revert()
            ngx.exit:revert()
        end)
    end)
end)