import { createClient, RedisClientType } from 'redis';
import { 
    RedisCollections1, 
    RedisCollections2, 
    RedisCollectionsArr1, 
    RedisCollectionsArr2, 
    RedisCollectionsHkey1String, 
    RedisCollectionsHkeyObj1, 
    RedisCollectionsSortedObj1,
    sortEd
} from './module/redis';
import { clusterRunOnce } from './clusterUtils';

const localKeys = [
    'hero', 'equip', 'shiwu', 'shop', 'email', 'gbtx', 'dxlt', 'fightLog', 'jjc', 'tanxian', 'chatPrivate', 'peijian'
    
];

const localVals: k_v<any> = {
    fightLog: {
        jjc: {},
        slzd: {},
        kbzz: {},
        ganhai: {},
    }
};

const crossKeys = ['fightLog'];
const crossVals: k_v<any> = {
    fightLog: {
        hbzbJfs: {},
        hbzbZbs: {},
        clsl: {}
    }
};

export let redisClient : RedisClientType;

export async function initRedis() {
    const proto = await import('@redis/json/dist/commands/index');

    //@ts-ignore
    // proto.transformRedisJsonArgument = function (json: any) {
    //     return JSON.stringify(json);
    // };
    // proto.transformRedisJsonNullReply = function (json: string) {
    //     if (json === null) return null;

    //     const a = decode(encode(json, 'iso-8859-1'), 'utf-8');
    //     const x = JSON.parse(a);
    //     return JSON.parse(decodeURIComponent(escape(json)));
    // };

    console.log('connect redis ......');
    redisClient = createClient({ url: G.argv.serverType == 'cross' ? G.config.crossRedisUrl : G.config.redisUrl });
    await redisClient.connect();
    if (G.config.dbIndex) await redisClient.select(G.config.dbIndex);
    G.redis = new _redis(redisClient as any);

    //启动前清理redis残余数据
    clusterRunOnce(async () => {
        await clearRedis();
        await setRedis();
    })
    if (G.config.cleanRedis) await redisClient.flushDb();
    console.log('connect redis succ');
}

async function clearRedis() {
    //现在redis的机制，只增不减，以下key，是会在getList等逻辑里重建的，因此
    //每次重启时，将这些key清空，避免占用redis内存
    await redisClient.del([
        G.redis.fromatKey('email'),
        G.redis.fromatKey('jjc'),
        G.redis.fromatKey('user'),
        G.redis.fromatKey('item'),
        G.redis.fromatKey('hero'),
        G.redis.fromatKey('equip'),
        G.redis.fromatKey('shiwu'),
        G.redis.fromatKey('tanxian'),
        G.redis.fromatKey('gbtx'),
        G.redis.fromatKey('dxlt'),
    ])
}

export async function setRedis() {
    let keys = G.argv.serverType == 'cross' ? crossKeys : localKeys;
    let vals = G.argv.serverType == 'cross' ? crossVals : localVals;
    
    for (let key of keys) {
        if (await G.redis.type(key as any) == null) {
            await G.redis.set(key as any, {});
        }
        if (vals[key]) {
            for (let val of Object.entries(vals[key])) {
                if (await G.redis.type(key as any, val[0]) == null) {
                    await G.redis.set(key as any, val[0], val[1]);
                }
            }
        }
    }
}


export class _redis implements redisJsonFun {
    logMsg = '';
    constructor(private redis: RedisClientType) {

    }
    log(str: string, pos: 'end' | 'start') {
        // if (pos == 'end') {
        //     console.log('redis cmd:', this. , str);
        //     this.logMsg = '';
        // } else if (pos == 'start') {
        //     this.logMsg = str;
        // }
    }
    fromatKey(key: string, state: 'zAdd' | 'zRange' | 'zRangeByScore' | 'zScore' | 'zRevRange' | 'zRem' | 'zRevRank' | 'zRank' | 'zCard' | 'hGet' | 'hmGet' | 'hGetAll' | 'hLen' | 'hSet' | 'hDel' | 'del' | 'numIncrBy' | 'type' | 'get' | 'set' | 'arrAppend' | 'arrPop' | 'arrLen' | 'arrInsert' | null) {
        let sid = G.config.serverId || 0;
        let fmtKey = `${G.config.projectName}_${G.argv.serverType == 'cross' ? `corss${sid}` : sid}_${key}`;
        state && this.log(state + ' ' + fmtKey, 'start');
        return fmtKey;
    }
    /**
     * redis路径只能以字母、美元符号或下划线开头
     */
    formatPath(args: string[], log = true) {
        args = args.map(str => G.formatRedisKey(str));
        let path = '.' + args.join('.');
        log && this.log(path, 'end');
        return path;
    }

    async hGet() {
        let _args = Array.from(arguments);
        let result = await this.redis.hGet(this.fromatKey(_args[0], 'hGet'), _args[1]);
        try{
            result = JSON.parse(result)
        } catch (err) {}
        return result
    }
    async hmGet() {
        let _args = Array.from(arguments);
        let result = await this.redis.hmGet(this.fromatKey(_args[0], 'hmGet'), _args[1]);
        try{
            for(let i in result) {
                result[i] = JSON.parse(result[i])
            }
        } catch(err) {}
        return result
    }

    async rawGet(){
        let _args = Array.from(arguments);
        return await this.redis.get(this.fromatKey(_args[0], 'get')) as any; 
    }

    async rawDel(){
        let _args = Array.from(arguments);
        return await this.redis.del(this.fromatKey(_args[0], 'del')) as any; 
    }

    async rawSet(){
        let _args = Array.from(arguments);
        return await this.redis.set(this.fromatKey(_args[0], 'set'), _args[1] as any, _args?.[2]||null ); 
    }


    async hGetAll() {
        let _args = Array.from(arguments);
        let result = await this.redis.hGetAll(this.fromatKey(_args[0], 'hGetAll'));
        if(result) {
            for(let i in result) {
                try{
                    result[i] = JSON.parse(result[i]) 
                } catch (err) {}
            }
        }
        return result
    }

    async hLen() {
        let _args = Array.from(arguments);
        let result = await this.redis.hLen(this.fromatKey(_args[0], 'hLen'));
        return result
    }

    async hSet() {
        let _args = Array.from(arguments);
        if(_args[2] instanceof Array || _args instanceof Object) _args[2] = JSON.stringify(_args[2])
        return this.redis.hSet(this.fromatKey(_args[0], 'hSet'), _args[1], _args[2]);
    }

    async hDel() {
        let _args = Array.from(arguments);
        return this.redis.hDel(this.fromatKey(_args[0], 'hDel'), _args);
    }

    async zAdd() {
        let _args = Array.from(arguments);
        return this.redis.zAdd(this.fromatKey(_args[0], 'zAdd'), _args[1]);
    }
    
    async zCard () {
        let _args = Array.from(arguments);
        return this.redis.zCard(this.fromatKey(_args[0], 'zAdd'));
    }

    
    /**
     * 获取指定索引范围排名
     * redis参数
     * ${type} 
     * ${min}
     * ${max}
     */
    async zRange() {
        let _args = Array.from(arguments);
        return await this.redis.zRange(this.fromatKey(_args[0], 'zRange'), _args[1], _args[2])
    }

    async zRevRange() {
        let _args = Array.from(arguments);
        //zRange在默认设定里，相同的score时，会将后插入的排在前面，而排行榜里，是期望先插入的排在前面
        //所以这里需要特殊处理
        let res = await this.redis.zRange(this.fromatKey(_args[0], 'zRange'), _args[1], _args[2], {REV: true})

        // let value = await this.redis.zRangeWithScores(this.fromatKey(_args[0], 'zRange'), _args[1], _args[2], {REV: true});
        // //自己排序，只有分数>时才交换排名，实现相同分数时不交换
        // value.sort((a,b)=>{
        //     return a.score > b.score ? -1 : 1
        // });
        // let res = [];
        // value.forEach(v=>{res.push(v.value)})
        return res
    }


    
    /**
     * 获取指定key排名
     * redis参数
     * ${type}
     * ${key}
     */
    async zRank() {
        let _args = Array.from(arguments);
        return await this.redis.zRank(this.fromatKey(_args[0], 'zRank'), _args[1])
    }
    async zScore() {
        let _args = Array.from(arguments);
        return await this.redis.zScore(this.fromatKey(_args[0], 'zScore'), _args[1])
    }

    /**获取指定key排名，倒叙 */
    async zRevRank() {
        let _args = Array.from(arguments);
        return await this.redis.zRevRank(this.fromatKey(_args[0], 'zRevRank'), _args[1]);
    }
    
    /**删除指定key的排名数据 */
    async zRem() {
        let _args = Array.from(arguments);
        return await this.redis.zRem(this.fromatKey(_args[0], 'zRem'), _args[1]);
    }

    async get() {
        if (await this.type(...arguments) == null) return null;

        let _args = Array.from(arguments);
        return await this.redis.json.get(this.fromatKey(_args[0], 'get'), { path: this.formatPath(_args.slice(1)) }) as any;
    }

    async gets() {
        let key = arguments[0];
        let _args = Array.from(arguments);
        let dataObj = {};

        if (_args.length <= 1) return [];

        if (key == 'user' && _args[1].length == 1) {
            return (await G.mongodb.collection('user').find({ uid: { $in: _args.slice(1).map(s => s[0]) } }).toArray()) as any;
        }

        for (let arg of _args.slice(1)) {
            let arr = arg;
            let path = this.formatPath(arr, false);
            dataObj[path] = await this.type(key, ...arr) == null ? null : true;
        }

        let paths = Object.keys(dataObj).filter(k => dataObj[k] == true);
        if (paths.length > 0) {
            let res = await this.redis.json.get(this.fromatKey(key, null), { path: paths });
            if (paths.length == 1) {
                dataObj[paths[0]] = res;
            } else {
                Object.assign(dataObj, res);
            }
        }

        return Object.values(dataObj);
    }

    async set() {

        let _args = Array.from(arguments);
        return await this.redis.json.set(this.fromatKey(_args[0], 'set'), this.formatPath(_args.slice(1, _args.length - 1)), _args[_args.length - 1]);
    }

    async del() {

        let _args = Array.from(arguments);
        return await this.redis.json.del(this.fromatKey(_args[0], 'del'), this.formatPath(_args.slice(1, _args.length)));
    }

    async type(...args: any[]) {

        let _args = Array.from(arguments);
        return await this.redis.json.type(this.fromatKey(_args[0], 'type'), this.formatPath(_args.slice(1))) as any;
    }

    async numIncrBy() {

        let _args = Array.from(arguments);
        return await this.redis.json.numIncrBy(this.fromatKey(_args[0], 'numIncrBy'), this.formatPath(_args.slice(1, _args.length - 1)), _args[_args.length - 1]) as number;
    }

    async arrLen() {
        let _args = Array.from(arguments);
        return await this.redis.json.arrLen(this.fromatKey(_args[0], 'arrLen'), this.formatPath(_args.slice(1))) as any;
    }

    async arrPop() {
        let _args = Array.from(arguments);
        return await this.redis.json.arrPop(this.fromatKey(_args[0], 'arrPop'), this.formatPath(_args.slice(1, _args.length - 1)), _args[_args.length - 1]) as any;
    }

    async arrAppend() {
        let _args = Array.from(arguments);
        return await this.redis.json.arrAppend(this.fromatKey(_args[0], 'arrAppend'), this.formatPath(_args.slice(1, _args.length - 1)), ...[].concat(_args[_args.length - 1])) as any;
    }

    async arrInsert() {
        let _args = Array.from(arguments);
        let _numIndex = _args.length - 2;
        return await this.redis.json.arrInsert(this.fromatKey(_args[0], 'arrInsert'), this.formatPath(_args.slice(1, _numIndex)), _args[_numIndex], ...[].concat(_args[_args.length - 1])) as any;
    }

    // 检查 redis 是否连接
    async chkRedis() {
        return this.redis.isOpen
    }

}

interface Document {
    [key: string]: any;
}

type Join<T extends unknown[], D extends string> = T extends [] ? '' : T extends [string | number] ? `${T[0]}` : T extends [string | number, ...infer R] ? `${T[0]}${D}${Join<R, D>}` : string;

type NestedPaths<Type, Depth extends number[]> = Depth['length'] extends 8 ? [] : Type extends string | number | boolean | Date | RegExp | Buffer | Uint8Array | ((...args: any[]) => any) | {
    _bsontype: string;
} ? [] : Type extends ReadonlyArray<infer ArrayType> ? [] | [number, ...NestedPaths<ArrayType, [...Depth, 1]>] : Type extends Map<string, any> ? [string] : Type extends object ? {
    [Key in Extract<keyof Type, string>]: Type[Key] extends Type ? [Key] : Type extends Type[Key] ? [Key] : Type[Key] extends ReadonlyArray<infer ArrayType> ? Type extends ArrayType ? [Key] : ArrayType extends Type ? [Key] : [
        Key,
        ...NestedPaths<Type[Key], [...Depth, 1]>
    ] : // child is not structured the same as the parent
    [
        Key,
        ...NestedPaths<Type[Key], [...Depth, 1]>
    ] | [Key];
}[Extract<keyof Type, string>] : [];

type KeysOfAType<TSchema, Type> = {
    [key in keyof TSchema]: NonNullable<TSchema[key]> extends Type ? key : never;
}[keyof TSchema];

type ArrayElement<Type> = Type extends ReadonlyArray<infer Item> ? Item : never;

type PropertyType<Type, Property extends string> = string extends Property ? unknown : Property extends keyof Type ? Type[Property] : Property extends `${number}` ? Type extends ReadonlyArray<infer ArrayType> ? ArrayType : unknown : Property extends `${infer Key}.${infer Rest}` ? Key extends `${number}` ? Type extends ReadonlyArray<infer ArrayType> ? PropertyType<ArrayType, Rest> : unknown : Key extends keyof Type ? Type[Key] extends Map<string, infer MapType> ? MapType : PropertyType<Type[Key], Rest> : unknown : unknown;

type NestedPathsOfType<TSchema, Type> = KeysOfAType<{
    [Property in Join<NestedPaths<TSchema, []>, '.'>]: PropertyType<TSchema, Property>;
}, Type>;

type MatchKeysAndValues<TSchema> = Readonly<{
    [Property in Join<NestedPaths<TSchema, []>, '.'>]?: PropertyType<TSchema, Property>;
} /**& {
        [Property in `${NestedPathsOfType<TSchema, any[]>}.$${`[${string}]` | ''}`]?: ArrayElement<PropertyType<TSchema, Property extends `${infer Key}.$${string}` ? Key : never>>;
    } & {
        [Property in `${NestedPathsOfType<TSchema, Record<string, any>[]>}.$${`[${string}]` | ''}.${string}`]?: any;
    } & Document*/>;

type obj1 = RedisCollections1;
type obj2 = RedisCollections2;
type arr1 = RedisCollectionsArr1;
type arr2 = RedisCollectionsArr2;
type hStr1 = RedisCollectionsHkey1String;
type hObj1 = RedisCollectionsHkeyObj1;
type sObj1 = RedisCollectionsSortedObj1;
type keys<T> = keyof T;
type hkeys<T> = keyof T;
type skeys<T> = keyof T;
type redisPathValueType = 'integer' | 'string' | 'object' | 'boolean' | 'array' | null;
type NumericKeys<T> = {
    [K in keyof T]: T[K] extends number ? K : never;
}[keyof T];

export interface redisJsonFun {
    /**
     * 向路径处的数组值追加一个或多个值。RedisJSON.arrAppend 
     */
    arrAppend<key extends keys<arr1>>(key: key, path: string, val: arr1[key][] | arr1[key]): Promise<number>;

    arrAppend<key extends keys<arr2>>(key: key, path: string, path1: string, val: arr2[key][] | arr2[key]): Promise<number>;

    /**
     * 向路径处的数组值插入一个或多个值。 RedisJSON.arrInsert 
     */
    arrInsert<key extends keys<arr1>>(key: key, path: string, index: number, val: arr1[key][] | arr1[key]): Promise<number>;

    arrInsert<key extends keys<arr2>>(key: key, path: string, path1: string, index: number, val: arr2[key][] | arr2[key]): Promise<number>;

    /**
     * 获取路径处数组值的长度 RedisJSON.arrLen 
     */
    arrLen<key extends keys<arr1>>(key: key, path: string): Promise<number>;

    arrLen<key extends keys<arr2>>(key: key, path: string, path1: string): Promise<number>;

    /**  
     * 从数组中移除并返回索引处的元素。弹出空数组会返回 Null。 RedisJSON.arrPop 
     * @param index 数组下标 如果为-1，这表示最后一个元素。
     */
    arrPop<key extends keys<arr1>>(key: key, path: string, index: number): Promise<arr1[key]>;

    arrPop<key extends keys<arr2>>(key: key, path: string, path1: string, index: number): Promise<arr2[key]>;

    /**
     * 删除路径上的值 RedisJSON.del 
     */
    del<key extends keys<obj1>>(key: key): Promise<number>;

    del<key extends keys<obj1>>(key: key, path: string): Promise<number>;

    del<key extends keys<obj1>, path extends keys<obj1[key]>>(key: key, path: string, path1: path): Promise<number>;

    del<key extends keys<obj2>>(key: key): Promise<number>;

    del<key extends keys<obj2>>(key: key, path: string): Promise<number>;

    del<key extends keys<obj2>>(key: key, path: string, path1: string): Promise<number>;

    del<key extends keys<obj2>, path extends keys<obj2[key]>>(key: key, path: string, path1: string, path2: path): Promise<number>;

    del<key extends keys<arr1>>(key: key): Promise<number>;

    del<key extends keys<arr1>>(key: key, path: string): Promise<number>;

    del<key extends keys<arr1>, path extends keys<arr1[key]>>(key: key, path: `${string}[${number}]`, path1: path): Promise<number>;

    del<key extends keys<arr2>>(key: key): Promise<number>;

    del<key extends keys<arr2>>(key: key, path: string): Promise<number>;

    del<key extends keys<arr2>>(key: key, path: string, path1: string): Promise<number>;

    del<key extends keys<arr2>, path extends keys<arr2[key]>>(key: key, path: string, path1: `${string}[${number}]`, path3: path): Promise<number>;

    del<key extends string>(key): Promise<number>;
    /**
     * 获取路径上的值 RedisJSON.get 
     * @returns 没有找到返回null
     * @example 
     * ```ts
     * //一层嵌套对象 
     * 
     * await G.redis.get('user', 'uid') //获取某个玩家的信息
     * await G.redis.get('user') //获取所有玩家
     * 
     * //二层嵌套对象 
     * 
     * await G.redis.get('hero', 'uid', '_id') //获取玩家的某个英雄
     * await G.redis.get('hero', 'uid') //获取玩家的所有英雄
     * await G.redis.get('hero') //获取所有玩家的所有英雄
     * 
     * ```
     */
    get<key extends keys<obj1>>(key: key): Promise<k_v<obj1[key]>>;

    get<key extends keys<obj2>>(key: key): Promise<k_v<k_v<obj2[key]>>>;

    get<key extends keys<arr1>>(key: key): Promise<k_v<arr1[key][]>>;

    get<key extends keys<arr2>>(key: key): Promise<k_v<k_v<arr2[key][]>>>;

    get<key extends keys<obj1>>(key: key, uid: string): Promise<obj1[key]>;

    get<key extends keys<obj2>>(key: key, uid: string): Promise<k_v<obj2[key]>>;

    get<key extends keys<arr1>>(key: key, k: `${string}[${number}]`): Promise<arr1[key]>;

    get<key extends keys<arr1>>(key: key, k: string): Promise<arr1[key][]>;

    get<key extends keys<arr2>>(key: key, k: string): Promise<k_v<arr2[key][]>>;

    get<key extends keys<arr1>, path extends keys<arr1[key]>>(key: key, k: `${string}[${number}]`, path: path): Promise<arr1[key][path]>;

    get<key extends keys<arr2>>(key: key, k: string, k1: `${string}[${number}]`): Promise<arr2[key]>;

    get<key extends keys<arr2>>(key: key, k: string, k1: string): Promise<arr2[key][]>;

    get<key extends keys<obj1>, path extends keys<obj1[key]>>(key: key, uid: string, path: path): Promise<obj1[key][path]>;

    get<key extends keys<obj2>>(key: key, uid: string, _id: string): Promise<obj2[key]>;

    get<key extends keys<arr2>, path extends keys<arr2[key]>>(key: key, k: string, k1: `${string}[${number}]`, k2: path): Promise<arr2[key][path]>;

    get<key extends keys<obj2>, path extends keys<obj2[key]>>(key: key, uid: string, _id: string, path: path): Promise<obj2[key][path]>;
    
    /**
     * 获取多个路径上的值 基于RedisJSON.get的封装 
     * @returns [val | null, val | null, ...] 需要注意的是会跟据传入参数的长度返回对应长度的数组 其中找不到的值为null
     * @example 
     * ```ts
     * //一层嵌套对象 
     * 
     * await G.redis.gets('user', ['bindUid1'], ['bindUid2']) //获取 [bindUid1的玩家数据, bindUid2的玩家数据];
     * await G.redis.gets('user', ['bindUid1', 'lv'], ['bindUid2', 'vip']) //获取 [bindUid1玩家的lv, bindUid2玩家的vip]
     * 
     * //二层嵌套对象 
     * 
     * await G.redis.get('hero', ['uid1'], ['uid2']) //获取 [uid玩家的所有英雄, uid2玩家的所有英雄]
     * await G.redis.get('hero', ['uid1', '_id1'], ['uid2', '_id1']) //获取 [uid玩家_id为'_id1'的英雄, uid2玩家_id为'_id1'的英雄]
     * await G.redis.get('hero', ['uid1', '_id1', 'lv'], ['uid2', '_id1', 'heroId']) //获取 [uid玩家_id为'_id1'的英雄的lv, uid2玩家_id为'_id1'的英雄的heroId]
     * 
     * ```
     */
    gets<key extends keys<arr2>, path extends keys<arr2[key]>>(key: key, ...paths: [string, `${string}[${number}]`, path][]): Promise<arr2[key][path][]>;

    gets<key extends keys<obj2>, path extends keys<obj2[key]>>(key: key, ...paths: [string, string, path][]): Promise<obj2[key][path][]>;

    gets<key extends keys<arr1>, path extends keys<arr1[key]>>(key: key, ...paths: [`${string}[${number}]`, path][]): Promise<arr1[key][path][]>;

    gets<key extends keys<arr2>>(key: key, ...paths: [string, `${string}[${number}]`][]): Promise<arr2[key][]>;

    gets<key extends keys<obj1>, path extends keys<obj1[key]>>(key: key, ...paths: [string, path][]): Promise<obj1[key][path][]>;

    gets<key extends keys<arr2>>(key: key, ...paths: [string, string][]): Promise<arr2[key][][]>;

    gets<key extends keys<obj2>>(key: key, ...paths: [string, string][]): Promise<obj2[key][]>;

    gets<key extends keys<obj1>>(key: key, ...paths: [string][]): Promise<obj1[key][]>;

    gets<key extends keys<obj2>>(key: key, ...paths: [string][]): Promise<k_v<obj2[key]>[]>;

    gets<key extends keys<arr1>>(key: key, ...paths: [`${string}[${number}]`][]): Promise<arr1[key][]>;

    gets<key extends keys<arr1>>(key: key, ...paths: [string][]): Promise<arr1[key][][]>;

    /**
     * 将路径上的数字值增加给定数字 RedisJSON.numIncrBy
     */
    numIncrBy<key extends keys<arr2>, path extends NumericKeys<arr2[key]>>(key: key, path: string, path1: `${string}[${number}]`, path2: path, by: number): Promise<number>;

    numIncrBy<key extends keys<obj2>, path extends NumericKeys<obj2[key]>>(key: key, path: string, path1: string, path2: path, by: number): Promise<number>;

    numIncrBy<key extends keys<arr1>, path extends NumericKeys<arr1[key]>>(key: key, path: `${string}[${number}]`, path1: path, by: number): Promise<number>;

    numIncrBy<key extends keys<obj1>, path extends NumericKeys<obj1[key]>>(key: key, path: string, path1: path, by: number): Promise<number>;

    /**
     * 设置路径上的值 RedisJSON.set
     */
    set<key extends keys<obj1>>(key: key, json: k_v<obj1[key]> | {}): Promise<'OK'>;

    set<key extends keys<obj2>>(key: key, json: k_v<k_v<obj2[key]>> | {}): Promise<'OK'>;

    set<key extends keys<arr1>>(key: key, json: k_v<arr1[key][]> | {}): Promise<'OK'>;

    set<key extends keys<arr2>>(key: key, json: k_v<k_v<arr2[key][]>> | {}): Promise<'OK'>;

    set<key extends keys<arr2>, path extends keys<arr2[key]>>(key: key, path1: string, path2: `${string}[${number}]`, path3: path, json: arr2[key][path]): Promise<'OK'>;

    set<key extends keys<arr1>>(key: key, path1: `${string}[${number}]`, json: arr1[key]): Promise<'OK'>;

    set<key extends keys<arr1>>(key: key, path1: string, json: arr1[key][] | []): Promise<'OK'>;

    set<key extends keys<arr2>>(key: key, path1: string, json: k_v<arr2[key][]> | {}): Promise<'OK'>;

    set<key extends keys<obj1>>(key: key, path1: string, json: obj1[key]): Promise<'OK'>;

    set<key extends keys<obj2>>(key: key, path1: string, json: k_v<obj2[key]> | {}): Promise<'OK'>;

    set<key extends keys<arr1>, path extends keys<arr1[key]>>(key: key, path1: `${string}[${number}]`, path2: path, json: arr1[key][path]): Promise<'OK'>;

    set<key extends keys<obj1>, path extends keys<obj1[key]>>(key: key, path1: string, path2: path, json: obj1[key][path]): Promise<'OK'>;

    set<key extends keys<obj2>>(key: key, path1: string, path2: string, json: obj2[key]): Promise<'OK'>;

    set<key extends keys<arr2>>(key: key, path1: string, path2: string, json: arr2[key][] | []): Promise<'OK'>;

    set<key extends keys<obj2>, path extends keys<obj2[key]>>(key: key, path1: string, path2: string, path3: path, json: obj2[key][path]): Promise<'OK'>;

    set<key extends keys<obj2>, path extends keys<obj2[key]>, path1 extends keys<obj2[key][path]>>(key: key, path1: string, path2: string, path3: path, path4: path1, json: obj2[key][path][path1]): Promise<'OK'>;

    //(property) set: <CommandOptions<ClientCommandOptions>>(...args: [key: RedisCommandArgument, value: number | RedisCommandArgument, options?: SetOptions] | [options: ...]) => Promise<...>
    rawSet<key extends string>(key:string | Buffer,value:string | Buffer,option?:any):Promise<string>;
    rawGet<key extends string>(key: string): Promise<string>;
    rawDel<key extends string>(key: string): Promise<string>;
    /**
     * 设置hash格式的数据
     * @param key 
     * @param hash 
     * @param value 
     */
    hSet<key extends hkeys<hStr1>>(key: key, hash:string, value: number | string):Promise<number>;

    hSet<key extends hkeys<hObj1>>(key: key, hash:string, value: hObj1[key]):Promise<number>;

    // 变量传key无法通过检测时，不做强制key类型验证。
    hSet<key extends string>(key: key, hash:string, value: any):Promise<number>;
    
    /**
     * 获取hash格式的数据
     * @param key 
     * @param hash 
     */
    hGet<key extends hkeys<hStr1>>(key: key, hash:string): Promise<string>;

    hGet<key extends hkeys<hObj1>>(key: key, hash:string): Promise<hObj1[key]>;
    
    // 变量传key无法通过检测时，不做强制key类型验证。
    hGet<key extends string>(key: key, hash:string): Promise<any>;
    
    hmGet<key extends hkeys<hObj1>>(key: key, hash:string[]): Promise<hObj1[key]>;
    hmGet<key extends string>(key: key, hash:string[]): Promise<any>;

    /**获取全部的hash数据 */
    hGetAll<key extends hkeys<hObj1>>(key: key):Promise<any>;

    hGetAll<key extends string>(key: key):Promise<any>;
    
    /**获取hash的长度 */
    hLen<key extends hkeys<hObj1>>(key: key):Promise<number>;

    hLen<key extends string>(key: key):Promise<number>;

    /**删除指定hash的某个field */
    hDel<key extends hkeys<hObj1>>(key: key, field: string):Promise<any>;

    hDel<key extends string>(key: key, field: string):Promise<any>;
    /**
     * 写入排名数据
     * @param key 
     */
    zAdd<key extends skeys<sObj1>>(key: key, member: sObj1[key]): Promise<number>;

    zAdd<key extends string>(key: key, member: sortEd|sortEd[]): Promise<number>;

    /**
     * 取出范围索引的排名数据
     * @param key 
     */
    zRange<key extends skeys<sObj1>>(key: key, min: number, max: number): Promise<string[]>;
    
    zRange<key extends string>(key: key, min: number, max: number): Promise<string[]>;
    
    zRevRange<key extends skeys<sObj1>>(key: key, min: number, max: number): Promise<string[]>;

    zRevRange<key extends string>(key: key, min: number, max: number): Promise<string[]>;

    /**
     * 取出指定member排名数据
     */
    zRank<key extends skeys<sObj1>>(key: key, member: string): Promise<number>;
    
    zRank<key extends string>(key: key, member: string): Promise<number>;
    
    /**
     * 取出指定member的分数
     * @param key 
     * @param member 
    */
    zScore<key extends skeys<sObj1>>(key: key, member: string): Promise<number>;

    zScore<key extends string>(key: key, member: string): Promise<number>;

    /**
     * 取出指定member排名数据-倒叙
     */
    zRevRank<key extends skeys<sObj1>>(key: key, member: string): Promise<number>;
    
    zRevRank<key extends string>(key: key, member: string): Promise<number>;
    
    /**
     * 删除指定member排名数据
    */
    zRem<key extends skeys<sObj1>>(key: key, member: string): Promise<number>;
    
    zRem<key extends string>(key: key, member: string): Promise<number>;

    /** */
    /**
     * 排行榜总数
     * @param key 
     */
    zCard<key extends skeys<sObj1>>(key: key): Promise<any>;

    zCard<key extends string>(key: key): Promise<any>;

    /***-
     * 获取路径上值的类型 RedisJSON.type
     */
    type<key extends keys<obj1>>(key: key): Promise<redisPathValueType>;

    type<key extends keys<obj1>>(key: key, path: string): Promise<redisPathValueType>;

    type<key extends keys<obj1>, path extends keys<obj1[key]>>(key: key, path: string, path1: path): Promise<redisPathValueType>;

    type<key extends keys<obj2>>(key: key): Promise<redisPathValueType>;

    type<key extends keys<obj2>>(key: key, path: string): Promise<redisPathValueType>;

    type<key extends keys<obj2>>(key: key, path: string, path1: string): Promise<redisPathValueType>;

    type<key extends keys<obj2>, path extends keys<obj2[key]>>(key: key, path: string, path1: string, path2: path): Promise<redisPathValueType>;

    type<key extends keys<arr1>>(key: key): Promise<redisPathValueType>;

    type<key extends keys<arr1>>(key: key, path: string): Promise<redisPathValueType>;

    type<key extends keys<arr1>, path extends keys<arr1[key]>>(key: key, path: `${string}[${number}]`, path1: path): Promise<redisPathValueType>;

    type<key extends keys<arr2>>(key: key): Promise<redisPathValueType>;

    type<key extends keys<arr2>>(key: key, path: string): Promise<redisPathValueType>;

    type<key extends keys<arr2>>(key: key, path: string, path1: string): Promise<redisPathValueType>;

    type<key extends keys<arr2>, path extends keys<arr2[key]>>(key: key, path: string, path1: `${string}[${number}]`, path3: path): Promise<redisPathValueType>;

    chkRedis: any

    fromatKey(key: string, state?: 'del' | 'numIncrBy' | 'type' | 'get' | 'set' | 'arrAppend' | 'arrPop' | 'arrLen' | 'arrInsert' | null);

}