---
--- Generated by EmmyLua(https://github.com/EmmyLua)
--- Created by hartnett.
--- DateTime: 2019/11/8 16:57
---

local core = require("apisix.core")

local redis = require("apisix.core.redis")

local util = require("apisix.plugins.exchange-mobile.util")
local active_code = require("apisix.plugins.exchange-mobile.active_code")
local send_notice = require("apisix.plugins.exchange-mobile.send_notice")

local fetch_local_conf = require("apisix.core.config_local").local_conf
local config = fetch_local_conf()

-- 设备状态标识
local STATE = {
    ALLOW = 0,
    NEW = 1,
    LOCKED = 2,
    BLOCK = 3,
}

-- 保存手机设备的信息，key为deviceid，值为设备信息的json
local function set_mobile_info(deviceid, mobile_info)
    -- 判断长度，防止插入空数据
    if #mobile_info > 10 then
        local redis_cli = redis.new()
        local key = config["prefix"]["device_info"]
        core.log.warn(string.format("key: %s, deviceid: %s, mobile_info: %s", key, deviceid, mobile_info))
        redis_cli:hmset(key, deviceid, mobile_info)
    end
end

-- 判断手机设备信息是否存在
local function exist_mobile_info(deviceid)
    local has = false
    local mobile_info = ""
    local redis_cli = redis.new()

    local key = config["prefix"]["device_info"]

    local res, err = redis_cli:hmget(key, deviceid)
    if err == nil and res ~= nil then
        if #res > 0 then
            if type(res[1]) == "string" then
                mobile_info = res[1]
                has = true
            end
        end
    end
    return has, mobile_info
end

-- 在特定的账户下新建用户
local function new_device(username, deviceid, device_info)
    local redis_cli = redis.new()
    local key = string.format("%s%s", config["prefix"]["user_prefix"], username)
    redis_cli:hmset(key, deviceid, device_info)
end

-- 删除设备及相关的信息
local function remove_device(username, deviceid)
    local redis_cli = redis.new()
    -- 删除账户下设备ID对应的信息
    redis_cli:del(string.format("%s%s", config["prefix"]["user_prefix"], username), deviceid)
    -- 删除某个设备下的用户信息
    redis_cli:del(string.format("%s%s", config["prefix"]["device_prefix"], deviceid), username)
end

-- 获取账户的状态
local function get_user_status(username)
    local key = string.format("%s%s", config["prefix"]["account_prefix"], username)
    local status = -1

    local redis_cli = redis.new()
    local res, err = redis_cli:hmget(key, "state")
    if err == nil and res ~= nil then
        if #res > 0 then
            if type(res[1]) == "string" then
                status = res[1]
            end
        end
    end

    return tonumber(status)
end

-- 注册新用户
local function new_user(username)
    local key = string.format("%s%s", config["prefix"]["account_prefix"], username)
    local redis_cli = redis.new()
    redis_cli:hset(key, "state", 0)
end

-- 获取特定用户的某个设备的信息，直接返回redis中的String
local function get_device(username, deviceid)
    local key = string.format("%s%s", config["prefix"]["user_prefix"], username)
    local device_info = ""
    local redis_cli = redis.new()

    local res, err = redis_cli:hmget(key, deviceid)
    if err == nil and res ~= nil then
        if #res > 0 then
            if type(res[1]) == "string" then
                device_info = res[1]
            end
        end
    end

    core.log.warn(string.format("key:%s, res: %s, err: %s, device_info: %s", key, res, err, device_info))

    return device_info
end

-- 获取特定用户某个设备的信息，返回一个table
local function get_device_info(username, deviceid)
    local device_info = {}
    local device_str = get_device(username, deviceid)
    if device_str ~= "" then
        device_info = core.json.decode(device_str)
    end

    return device_info
end

-- 获取特定设备的状态信息
local function get_device_status(username, deviceid)
    local state = -1
    local device_info = get_device_info(username, deviceid)
    if next(device_info) then
        state = device_info["state"]
    end

    return tonumber(state)
end

-- 设备状态设置，0表示激活
local function set_device_status(username, deviceid, state)
    local device_info = get_device_info(username, deviceid)
    device_info["state"] = state
    local device_str = core.json.encode(device_info)

    local key = string.format("%s%s", config["prefix"]["user_prefix"], username)

    local redis_cli = redis.new()
    redis_cli:hset(key, deviceid, device_str)
end

-- 添加用户信息到设备列表中
local function add_user_to_devicelist(username, device_id)
    local key = string.format("%s%s", config["prefix"]["device_prefix"], device_id)
    local now = ngx.localtime()

    local redis_cli = redis.new()
    redis_cli:hset(key, username, now)
end

-- 激活设备，0
local function active_device(username, deviceid)
    set_device_status(username, deviceid, STATE.ALLOW)
    add_user_to_devicelist(username, deviceid)
end

-- 恢复设备，1
local function restore_device(username, deviceid)
    set_device_status(username, deviceid, STATE.NEW)
end

-- 忽略设备，3
local function ignore_device(username, deviceid)
    set_device_status(username, deviceid, STATE.BLOCK)
end

-- 锁定设备，2
local function lock_device(username, deviceid)
    set_device_status(username, deviceid, STATE.LOCKED)
end

-- 设备激活状态设置，有效期为60秒
local function set_device_active_status(username, device_id)
    local redis_cli = redis.new()

    local key = string.format("active_%s_%s", username, device_id)
    redis_cli:set(key, device_id)
    redis_cli:expire(key, 60)
end

-- 判断设备是否处于1分钟内激活过
local function exist_device_active(username, device_id)
    local redis_cli = redis.new()

    local result = false
    local key = string.format("active_%s_%s", username, device_id)

    local res, err = redis_cli:get(key)
    if err == nil and res ~= nil and type(res) == "string" and res == device_id then
        result = true
    end

    core.log.warn(string.format("key: %s, res: %s, err: %s, result: %s", key, res, err, result))

    return result
end

-- 通过username获取设备列表
local function get_device_list(username)
    local redis_cli = redis.new()

    local device_list = {}
    local key = string.format("%s%s", config["prefix"]["user_prefix"], username)

    local res, err = redis_cli:hvals(key)
    if err == nil and res ~= nil then
        if type(res) == "table" then
            for _, v in ipairs(res) do
                if #v > 10 then
                    core.log.warn(string.format("device: %s, type: %s", v, type(v)))
                    table.insert(device_list, device_info)
                end
            end
        end
    end

    return device_list
end

-- 通过设备ID获取用户列表
local function get_user_list(device_id)
    local redis_cli = redis.new()

    local user_list = {}
    local key = string.format("%s%s", config["prefix"]["device_prefix"], device_id)

    local res, err = redis_cli:hkeys(key)
    if err == nil and res ~= nil and type(res) == "table" then
        user_list = res
    end

    return user_list
end

-- 设备激活逻辑
local function do_device_active(ctx, username, device_id, device_str)
    local device_info = core.json.decode(device_str)
    local device_type = device_info["devicetype"] or ""
    local src_ip = util.get_user_srcip(ctx)
    local user_agent = core.request.header(ctx, "user-agent") or ""

    -- 判断设备是否在一分钟之内激活过
    if exist_device_active(username, device_id) then
        core.log.warn(string.format("user: %s ip: %s device: %s, Activation frequency is too fast, ignore request",
                username, src_ip, device_id))
    else
        set_device_active_status(username, device_id)

        -- 保存设备来源IP到config["prefix"]["device_name"]中
        active_code.set_device_srcip(device_id, src_ip)
        local phone_imei = ""
        local phone_num = ""
        local code = active_code.set_active_code(username, device_id, device_str)

        core.log.warn(string.format("Send activation code: %s to %s, user: %s, src_ip: %s, device_id: %s, device_str: %s",
                code, phone, username, src_ip, device_id, device_str))

        local has, mobile_info = exist_mobile_info(device_id)
        if has then
            local info = util.wbxml2info(mobile_info)
            if next(info) then
                local phone_model = info["model"] or ""
                phone_num = info["phone"] or ""
                phone_imei = info["imei"] or device_id
                device_type = phone_model or device_type
                core.log.warn(string.format("phone_model: %s, imei: %s, phone_num: %s",
                        phone_model, phone_imei, phone_num))
            end
        end

        local send_status = send_notice.send_active_code(username, device_id, "", code, src_ip, device_type, phone_imei, phone_num)
        -- 用完之后删除验证码，防止重复使用
        if send_status then
            active_code.del_active_code_flag(username, device_id)
        end
    end
end

-- 获取当前用户的设备数量
local function get_device_num(username)
    local device_list = get_device_list(username)
    local num = #device_list
    return num
end

local _M = {
    set_mobile_info = set_mobile_info,
    exist_mobile_info = exist_mobile_info,
    new_device = new_device,
    remove_device = remove_device,
    get_user_status = get_user_status,
    new_user = new_user,
    get_device = get_device,
    get_device_info = get_device_info,
    get_device_status = get_device_status,
    set_device_status = set_device_status,
    add_user_to_devicelist = add_user_to_devicelist,
    active_device = active_device,
    restore_device = restore_device,
    ignore_device = ignore_device,
    lock_device = lock_device,
    set_device_active_status = set_device_active_status,
    exist_device_active = exist_device_active,
    get_device_list = get_device_list,
    get_user_list = get_user_list,
    do_device_active = do_device_active,
    get_device_num = get_device_num,
}

return _M