#!/usr/bin/env resty

local script_path = debug.getinfo(1).source:sub(2)

local function trim(s)
    return (s:gsub("^%s*(.-)%s*$", "%1"))
end

local function execute_cmd(cmd)
    local t = io.popen(cmd)
    local data = t:read("*all")
    t:close()
    return data
end

local apioak_home
if script_path:sub(1, 4) == '/usr' or script_path:sub(1, 4) == '/bin' then
    apioak_home = "/usr/local/apioak"
    package.cpath = "/usr/local/apioak/deps/lib64/lua/5.1/?.so;"
            .. "/usr/local/apioak/deps/lib/lua/5.1/?.so;"
            .. package.cpath

    package.path = "/usr/local/apioak/deps/share/lua/5.1/apioak/lua/?.lua;"
            .. "/usr/local/apioak/deps/share/lua/5.1/?.lua;"
            .. "/usr/share/lua/5.1/apioak/lua/?.lua;"
            .. "/usr/local/share/lua/5.1/apioak/lua/?.lua;"
            .. package.path
else
    apioak_home = trim(execute_cmd("pwd"))
    package.cpath = apioak_home .. "/deps/lib64/lua/5.1/?.so;"
            .. package.cpath

    package.path = apioak_home .. "/apioak/?.lua;"
            .. apioak_home .. "/deps/share/lua/5.1/?.lua;"
            .. package.path
end

local openresty_bin = trim(execute_cmd("which openresty"))
if not openresty_bin then
    error("can not find the openresty.")
end

local openresty_launch = openresty_bin .. [[  -p ]] .. apioak_home .. [[ -c ]]
        .. apioak_home .. [[/conf/nginx.conf]]


local function get_config()
    local res, err = io.open(apioak_home .. "/conf/apioak.yaml", "r")
    if not res then
        print("Config Loading         ...FAIL(" .. err ..")")
        os.exit(1)
    else
        print("Config Loading         ...OK")
    end

    local config_content = res:read("*a")
    res:close()

    local yaml = require("tinyyaml")
    local config_table = yaml.parse(config_content)
    if not config_table or type(config_table) ~= "table" then
        print("Config Parse           ...FAIL")
        os.exit(1)
    else
        print("Config Parse           ...OK")
    end

    return config_table, nil
end


local function validate_database()
    local res, err = get_config()
    if not res.database then
        print("Config Database        ...FAIL(Undefined)")
        os.exit(1)
    else
        print("Config Database        ...OK")
    end

    local db_config = res.database

    local mysql  = require("resty.mysql")
    res, err = mysql:new()
    if not res then
        print("Database Init          ...FAIL(".. err ..")")
        os.exit(1)
    else
        print("Database Init          ...OK")
    end
    local db = res

    res, err = db:connect({
        host     = db_config.host     or "127.0.0.1",
        port     = db_config.port     or 3306,
        database = db_config.db_name  or "apioak",
        user     = db_config.user     or "apioak",
        password = db_config.password or ""
    })

    if not res then
        print("Database Connect       ...FAIL(".. err ..")")
        os.exit(1)
    else
        print("Database Connect       ...OK")
    end

    res, err = db:query("SELECT version() AS version")
    if not res then
        print("Database Query Version ...FAIL(".. err ..")")
        os.exit(1)
    else
        print("Database Query Version ...OK")
    end

    local db_version = res[1].version
    local db_version_num = tonumber(string.match(db_version, "^%d+%.%d+"))
    if string.find(db_version, "MariaDB") then
        if db_version_num < 10.2 then
            print("Database Version       ...FAIL(MariaDB version be greater than 10.2)")
            os.exit(1)
        else
            print("Database Version       ...OK")
        end
    else
        if db_version_num < 5.7 then
            print("Database Version       ...FAIL(MySQL version be greater than 5.7)")
            os.exit(1)
        else
            print("Database Version       ...OK")
        end
    end

    res, err = db:query("SHOW tables")
    if not res then
        print("Database Query Tables  ...FAIL(".. err ..")")
        os.exit(1)
    else
        print("Database Query Tables  ...OK")
    end

    local db_tables = {}
    local conf_tables = db_config.tables
    local table_field = 'Tables_in_' .. db_config.db_name
    for i = 1, #res do
        table.insert(db_tables, res[i][table_field])
    end
    if table.sort(db_tables) == table.sort(conf_tables) then
        print("Database Tables        ...OK")
    else
        print("Database Tables        ...FAIL")
    end
end

local _M = {}


function _M.help()
    print([[
Usage: apioak [action] <argument>
help:       show this message, then exit
start:      start the apioak server
stop:       stop the apioak server
restart:    restart the apioak server
reload:     reload the apioak server
test:       test the apioak nginx config
env:        check apioak running environment
]])
end


function _M.start()
    local cmd = openresty_launch
    os.execute(cmd)
end


function _M.stop()
    local cmd = openresty_launch .. [[ -s stop]]
    os.execute(cmd)
end


function _M.restart()
    _M.stop()
    _M.start()
end


function _M.reload()
    local cmd = openresty_launch .. [[ -s reload]]
    os.execute(cmd)
end


function _M.test()
    local cmd = openresty_launch .. [[ -t]]
    os.execute(cmd)
end


function _M.init()
    local logs = io.open(apioak_home .. "/logs", "rb")
    if not logs then
        execute_cmd("mkdir -p " .. apioak_home .. "/logs")
    else
        logs:close()
    end
end


function _M.env()
    local nginx_path = trim(execute_cmd("which openresty"))
    if not nginx_path then
        print("OpenResty PATH         ...FAIL(OpenResty not found in system PATH)")
        os.exit(1)
    else
        print("OpenResty PATH         ...OK")
    end


    if ngx.config.nginx_version < 1015008 then
        print("OpenResty Version      ...FAIL(OpenResty version must be greater than 1.15.8)")
        os.exit(1)
    else

        print("OpenResty Version      ...OK")
    end

    validate_database()
end


local cmd_action = arg[1]
if not cmd_action then
    return _M.help()
end


if not _M[cmd_action] then
    print("invalid argument: ", cmd_action, "\n")
    return
end


_M[cmd_action](arg[2])
