package com.sptg.common.security.service.impl;

import com.sptg.common.core.beans.UserBean;
import com.sptg.common.core.constant.HttpConstant;
import com.sptg.common.core.constant.SymbolConstant;
import com.sptg.common.core.util.CookieUtils;
import com.sptg.common.core.util.JsonUtils;
import com.sptg.common.security.service.SecurityServiceInterface;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * title: BaseRedisSecurityService
 * package: com.sptg.common.security.security.impl
 * description: Redis安全接口抽象类
 *
 *                  
 *                 
 */
@RequiredArgsConstructor
public abstract class BaseRedisSecurityService<Account extends UserBean> implements SecurityServiceInterface<Account> {

    private final RedisTemplate<String,String> redisTemplate;

    /* -------------------------------------------------------------------------------------------------------------- */

    @Override
    public String createUserToken(Account account) {
        //  生成Token 用户类型：UUID
        String token = UUID.randomUUID().toString();
        account.setLoginToken(token);
        this.updateAccount(account);
        return token;
    }

    @Override
    public void removeUserToken() {
        //  获得用户访问令牌
        String token = this.getTokenByRequest();
        if (!StringUtils.isEmpty(token)){
            this.removeUserToken(token);
            //  删除Cookie
            CookieUtils.deleteCookie(HttpConstant.ACCESS_TOKEN);
        }
    }

    @Override
    public boolean isLogin() {
        String token = this.getTokenByRequest();
        if (!StringUtils.isEmpty(token)){
            String key = this.generateKey(token);
            //  判断key是否存在
            return this.redisTemplate.hasKey(key);
        }
        return false;
    }

    /**
     * 功能描述: 生成Key
     * @param token 登陆令牌
     * @return String
     *                  
     *                       
     */
    private String generateKey(String token){
        return this.getCacheName() + token;
    }

    @Override
    public Account getOnLineUser() {
        String token = this.getTokenByRequest();
        if (!StringUtils.isEmpty(token)) {
            String key = this.generateKey(token);
            //  从缓存中获取用户信息
            String json = this.redisTemplate.opsForValue().get(key);
            if (!StringUtils.isEmpty(json)) {
                //  更新缓存有效期
                this.redisTemplate.expire(key, this.getTimeOut(), TimeUnit.SECONDS);
                return jsonToPojo(json);
            }
        }
        return null;
    }

    /**
     * 从请求中获取用户令牌
     * @return String
     */
    protected abstract String getTokenByRequest();

    /**
     * 获取缓存名称
     * @return String
     */
    protected abstract String getCacheName();

    /**
     * 获取登陆超时时间
     * @return 秒
     */
    protected abstract long getTimeOut();
    
    /**
     * 功能描述: json转账号类型
     * @param json 账号json
     * @return Account 账号类型
     *                  
     *                       
     */
    protected abstract Account jsonToPojo(String json);

    @Override
    public List<Account> getOnLineUserList() {
        //  获取缓存中的所有key
        Set<String> keys = this.redisTemplate.keys(this.getCacheName() + SymbolConstant.ASTERISK);
        if (null == keys){
            return new ArrayList<>(0);
        }
        List<Account> onLineUserList = new ArrayList<>(keys.size());
        keys.forEach(key -> {
            String json = this.redisTemplate.opsForValue().get(key);
            Account account = this.jsonToPojo(json);
            onLineUserList.add(account);
        });
        return onLineUserList;
    }

    @Override
    public void removeUserToken(String token) {
        //  创建Key
        String key = this.generateKey(token);
        //  将缓存中的用户信息删除
        this.redisTemplate.delete(key);
    }

    @Override
    public void updateAccount(Account account) {
        String key = this.generateKey(account.getLoginToken());
        String json = JsonUtils.objectToJson(account);
        this.redisTemplate.opsForValue().set(key,json);
        this.redisTemplate.expire(key, this.getTimeOut(), TimeUnit.SECONDS);
    }
}
