-- Load essential libraries
local config = require "sm.config"
local redis = require "sm.utils.redis"
local ssl = require "ngx.ssl"
local config_fetcher = require "sm.utils.config_fetcher"
local cjson = require "cjson"
local string_utils = require "sm.utils.string_utils"

-- Variables
local ssl_server_name = ssl.server_name
local ssl_clear_certs = ssl.clear_certs
local ngx_re_match = ngx.re.match
local log = ngx.log
local ngx_exit = ngx.exit
local ERROR = ngx.ERROR
local ERR = ngx.ERR
-- local string_lower = string.lower
-- local os_getenv = os.getenv
-- local server_id = string_lower(os_getenv("SERVER_ID"))

-- Get TLS SNI
local server_name, err = ssl_server_name()
if not server_name or err ~= nil then
    -- Fallback to default cert
    return log(ERR, "[SSL] Failed to get server name:", err)
end

log(ngx.INFO, "[SSL] server_name: " .. server_name)

-- Regex to see if sever name is subdomain of default domain
local match = ngx_re_match(server_name, "^(.*[a-zA-Z0-9].*\\.lightpath-cdn\\.net)$")
if match then
    -- Use default cert
    return
end

-- Connect to Redis
local ok, err = redis.connect(config["redis"])
if not ok then
    -- Fallback to default cert, error will be handled in access
    return log(ERR, "[SSL] Failed to connect to Redis: ", err)
end

-- Get hostname config
log(ngx.INFO, "[SSL] fetching hostname config for " .. server_name)
local hostname
local err
hostname, _, err = config_fetcher.hostname(redis, server_name)
if hostname == nil or err then
    if string_utils.is_root_domain(server_name) then
        log(ERR, "[SSL] no hostname config found for " .. server_name)
        -- Always close Redis and fallback to default cert, error will be handled in access
        return redis.close()
    else
        -- 再查询是否存在泛域名可以匹配
        log(ngx.INFO, "[SSL] no hostname config found for " .. server_name .. ", try to match wildcard")
        -- 从域名中提取根域名
        local root_domain = string_utils.get_root_domain(server_name)
        hostname, _, err = config_fetcher.hostname(redis, "*." .. root_domain)
        if hostname == nil or err then
            log(ERR, "[SSL] no hostname config found for " .. server_name)
            -- Always close Redis and fallback to default cert, error will be handled in access
            return redis.close()
        end
    end
end

-- 设置自定义变量
ngx.ctx.hostname = hostname
ngx.ctx.zone_id = hostname["key"]

-- Lookup certificate in cache or fetch from Ambassador
local certificate, private_key, cache_status, err = config_fetcher.ssl(redis, hostname["key"])

if err then
    log(ERR, "[SSL] error fetching ssl config: " .. cjson.encode(err))
    -- Fallback to default cert
    redis.close()
    return log(ERR, "[SSL] ", err)
end

if not certificate or not private_key then
    log(ERR, "[SSL] no ssl config found for " .. server_name)
    -- Fallback to default cert
    redis.close()
    return log(ERR, "[SSL] no ssl config found for " .. server_name)
end

-- Clear default ssl cert and key at the very end to ensure fallback to default ssl certs work
local ok, err = ssl_clear_certs()
if not ok then
    redis.close()
    log(ERR, "[SSL] Failed to clear default certificate: ", err)
    return ngx_exit(ERROR)
end

-- 解析出 cdata 类型的证书值，你可以用 lua-resty-lrucache 缓存解析结果
local cert, err = ssl.parse_pem_cert(certificate)
if not cert or err then
    ngx.log(ngx.ERR, "failed to parse PEM cert: ", err)
    return
end

ssl.set_cert(cert)

local pkey, err = ssl.parse_pem_priv_key(private_key)
if not pkey or err then
    ngx.log(ngx.ERR, "failed to parse pem key: ", err)
    return
end
ssl.set_priv_key(pkey)

redis.close()
