local kong_meta = require "kong.meta"

local InnerBasicAuth = {PRIORITY = 1097, VERSION = kong_meta.version}

local function extract_authorization(authorization)
    local auth_str = string.match(authorization, "%s*[Bb]asic%s*(.*)$")
    if not auth_str then
        return ""
    end
    return auth_str
end

function validate_auth(auth_info, conf)
    if auth_info == nil then
        kong.log.err("auth_info is nil.")
        return false
    end
    local env_type = auth_info["env_type"]
    if env_type ~= conf.env_type then
        kong.log.err(string.format("env_type check failed. %s != %s.", env_type,
                                   conf.env_type))
        return false
    end
    local auth_str = auth_info["auth_str"]
    local key_list_str = conf.authkey_list
    for v in string.gmatch(key_list_str, '([^,]+)') do
        if v == auth_str then
            return true
        end
    end
    kong.log.err(string.format(
                     "authorization header %s is not in authkey_list.", auth_str))
    return false
end

function parse_auth_key(auth_str)
    local ret_dict = {}
    local kv_pairs = {}
    local v_items = {}
    local decoded = ngx.decode_base64(auth_str)
    if decoded == nil then
        kong.log.err(string.format("parse_auth_key %s failed, decode_base64.",
                                   auth_str))
        return nil
    end
    for word in string.gmatch(decoded, '([^:]+)') do
        table.insert(kv_pairs, word)
    end
    if table.getn(kv_pairs) ~= 4 then
        kong.log.err(string.format(
                         "parse_auth_key %s(%s) failed, invalid length. %d ",
                         auth_str, decoded, table.getn(kv_pairs)))
        return nil
    end
    ret_dict["service"] = kv_pairs[1]
    ret_dict["env_type"] = kv_pairs[2]
    ret_dict["auth_str"] = auth_str
    return ret_dict
end

function get_auth_info()
    if not kong.request.get_header("Authorization") then
        kong.log.err("get authorization header failed.")
        return nil
    end
    local auth_str = extract_authorization(
                         kong.request.get_header("Authorization"))
    if auth_str == "" then
        kong.log.err("extract authorization header failed.")
        return nil
    end
    return parse_auth_key(auth_str)
end

function InnerBasicAuth:access(conf)
    local auth_info = get_auth_info()
    if auth_info == nil then
        kong.response.set_header("X-Debug-Trace-Id",
                                 kong.ctx.shared.trace_id or "-")
        kong.response.exit(401, response, {})
    end
    if not validate_auth(auth_info, conf) then
        kong.response.set_header("X-Debug-Trace-Id",
                                 kong.ctx.shared.trace_id or "-")
        kong.response.exit(401, response, {})
    end
    kong.service.request.clear_header("authorization")
    kong.service.request.add_header("x-request-type", "inner")
    kong.service.request.add_header("x-request-service", auth_info["service"])
end

return InnerBasicAuth
