import {Singleton} from "typescript-ioc";
import {UserInfo} from 'user/UserInfo'
import {StringUtils} from 'utils/StringUtils'
import {Context, logger, MsToken, OpResult, RedisClient} from "mslib";
import {v4} from 'uuid'

@Singleton
export class RedisTokenRepository {

    private redisClient?: RedisClient = undefined;
    private token_expires = "node_token_expires:"
    private token_user_id = "node_token_user_id:"

    /**
     * 初始化Redis客户端，用于管理鉴权Token
     */
    async init() {
        if (this.redisClient) {
            return;
        }
        const host = Context.getEnv('auth.redis.host')
        const port = Context.getEnv('auth.redis.port')
        const password = Context.getEnv('auth.redis.password') || ''
        const database = Context.getEnv('auth.redis.database') || 0
        if (!host || !port) {
            throw Error('未设置环境变量 [auth.redis]')
        }
        this.redisClient = new RedisClient(host, +port, password, +database);
    }

    /**
     * 添加用户信息
     * @param userInfo 用户信息
     * @param expires 过期时间
     */
    async addUserToken(userInfo: UserInfo, expires: number, autoRefresh: boolean = true): Promise<OpResult<MsToken>> {
        if (this.redisClient == null) {
            return OpResult.error("Error RedisClient Not Initialize!")
        }
        const token = StringUtils.base64Encode(userInfo.userId + '@' + v4() + '@' + new Date().getTime())
        const success = await this.redisClient.set(token, JSON.stringify(userInfo), expires)
        await this.redisClient.set(this.token_user_id + userInfo.userId, token, expires)

        if (autoRefresh) {
            await this.redisClient.set(this.token_expires + token, JSON.stringify({expires: expires}), expires)
        }
        if (success) {
            return OpResult.success("SUCCESS", {token: token, expires: expires} as MsToken)
        } else {
            return OpResult.error("Error Redis set command failure")
        }
    }


    /**
     * 获取用户信息
     * @param token Token
     * @param userInfo 用户信息
     * @param expires 过期时间
     */
    async getUserToken(token: string): Promise<OpResult<UserInfo>> {
        if (this.redisClient == null) {
            return OpResult.error("Error RedisClient Not Initialize!")
        }
        const data = await this.redisClient.get(token)
        if (data) {
            return OpResult.success("", JSON.parse(data))
        } else {
            return OpResult.error("Error Redis set command failure")
        }
    }

    /**
     * 修改用户信息
     * @param userInfo 用户信息
     */
    async updateUserInfo(userInfo: UserInfo): Promise<OpResult<boolean>> {
        if (this.redisClient == null) {
            return OpResult.error("Error RedisClient Not Initialize!")
        }
        const token = await this.redisClient.get(this.token_user_id + userInfo.userId);
        if (!token) {
            return OpResult.error("token is not exists ", false)
        }
        const expires = await this.redisClient.ttl(token)
        const success = await this.redisClient.set(token, JSON.stringify(userInfo), expires)
        if (success) {
            return OpResult.success("", success)
        } else {
            return OpResult.error("Error Redis set command failure")
        }
    }


    /**
     * 删除Token
     * @param token Token
     */
    async removeUserToken(token: string): Promise<boolean> {
        return await this.redisClient.delete(token)
    }


    /**
     * 设置Token过期时间
     * @param token Token
     */
    async setExpire(token: string, expire: number): Promise<boolean> {
        return await this.redisClient.expire(token, expire);
    }

    /**
     * 重置Token 过期时间
     * @param token Token
     */
    async resetExpires(userInfo: UserInfo, expires: number = 0): Promise<OpResult<any>> {
        try {
            const token = await this.redisClient.get(this.token_user_id + userInfo.userId);
            if (!token) {
                return OpResult.error("token does not exist")
            }
            const key = this.token_expires + token;
            const data = await this.redisClient.get(key);
            if (expires == 0 && data) {
                logger.info("用户Token 自动刷新成功")
                const expiresConfig = JSON.parse(data);
                expires = expiresConfig.expires || 7200
                await this.setExpire(key, expires);
            }
            await this.setExpire(token, expires);
            await this.setExpire(this.token_user_id + userInfo.userId, expires);
            return OpResult.success("OK")
        } catch (e) {
            logger.error(e)
        }
    }

    /**
     * 获取当前Redis客户端
     */
    getRedisClient(): RedisClient {
        return this.redisClient!!
    }
}