/**
 * redis模块
 * @date 2022-03
 * @author 何华东
 */

import { logger } from "mslib";
import { IocConfigProvider } from "./Config";
import { ConfigCenterConfigProvider } from "./ConfigCenter";
import { IS_DEBUG, IS_PARK, IS_PROD } from "./Contants";
import { throttle1 } from "./Utils";
import { init as init_i18n } from "./Global";
const IORedis = require("ioredis");

/**
 * redis客户端实例，基于ioredis插件
 * 
 * 配置优先级：
 * 
 * 1.ioc配置
 * 
 * 2.配置中心
 */
export let redisClient = null;

init();

async function getRedisPwdFromSqlite() {
    let pwd;

    const knexInstance = require('knex')({
        client: 'sqlite3',
        connection: {
            filename: "/home/keytop/data/lotconfig.db"
        }
    });

    let rows = await knexInstance('t_config').where({ session: 'redis', name: 'password' });
    if (rows && rows.length > 0 && rows[0].value) pwd = rows[0]?.value;

    return pwd;
}

async function init() {
    try {
        let config = IocConfigProvider.getIORedisConfig();
        if (!config) config = await ConfigCenterConfigProvider.getRedisConfig();
        if (!config) return;

        //场端环境&redis未配置密码，则自动从sqlite获取redis密码
        if (IS_PARK && !config.password) {
            try {
                config.password = await getRedisPwdFromSqlite();
            } catch (error) {
                logger.error('从sqlite获取redis密码失败', error);
            }
        }

        let logFunc = throttle1((error) => { logger.error(`redis`, error); });
        redisClient = new IORedis(Object.assign({ lazyConnect: true }, config));

        redisClient.on("error", error => {
            if (error.code === 'ECONNREFUSED') {
                logFunc(error);
            } else {
                logger.error(error);
            }
        });

        logger.info(`redis客户端实例创建成功,host:${config.host || 'localhost'}`);

        init_i18n();
    } catch (error) {
        logger.error('redis客户端实例创建失败', error);
    }
}

/**
 * redis分布式锁
 */
export function RedisLock(key: ((...args) => string) | string, value: string, ex: number): MethodDecorator {
    return function (target: Object, propertyKey: string, descriptor: PropertyDescriptor) {
        let method = descriptor.value;

        descriptor.value = async function (...args) {
            let _key = typeof key === 'function' ? key(args) : key;
            let res = await redisClient.set(_key, value, 'NX', 'EX', ex);
            if (res !== 'OK') return;

            //自动续约todo...

            try {
                return await method.apply(this, args);
            } catch (error) {
                throw error;
            } finally {
                await redisClient.del(_key);
            }
        }
    }
}