package com.zd.common.security.service;

import com.zd.common.core.constant.CacheConstants;
import com.zd.common.core.constant.Constants;
import com.zd.common.core.utils.*;
import com.zd.common.core.utils.ip.IpUtils;
import com.zd.common.redis.service.RedisService;
import com.zd.system.api.model.LoginUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * token验证处理
 *
 * @author zd
 */
@Component
public class TokenService {
    @Autowired
    private RedisService redisService;

    private static final long EXPIRE_TIME = Constants.TOKEN_EXPIRE * 60;

    private static final long APP_EXPIRE_TIME = 30;

    private static final String ACCESS_TOKEN = CacheConstants.LOGIN_TOKEN_KEY;

    protected static final long MILLIS_SECOND = 1000;

    /**
     * 创建令牌
     */
    public Map<String, Object> createToken(LoginUser loginUser) {
        Map<String, Object> map = createCommonToken(loginUser, EXPIRE_TIME);
        redisService.setCacheObject(ACCESS_TOKEN + map.get("access_token"), loginUser, EXPIRE_TIME, TimeUnit.SECONDS);
        return map;
    }


    /**
     * 创建令牌
     */
    public Map<String, Object> createProgramToken(LoginUser loginUser) {
        Map<String, Object> map = createCommonToken(loginUser, APP_EXPIRE_TIME);
        redisService.setCacheObject(ACCESS_TOKEN + map.get("access_token"), loginUser, APP_EXPIRE_TIME, TimeUnit.DAYS);
        return map;
    }

    /**
     * 创建令牌公共方法
     *
     * @param loginUser
     * @return
     */
    private Map<String, Object> createCommonToken(LoginUser loginUser, Long expiresIn) {
        // 生成token
        String token = IdUtils.fastUUID();
        loginUser.setToken(token);
        loginUser.setUserid(loginUser.getSysUser().getUserId());
        loginUser.setUsername(loginUser.getSysUser().getUserName());
        loginUser.setNickName(loginUser.getSysUser().getNickName());
        loginUser.setIpaddr(IpUtils.getIpAddr(ServletUtils.getRequest()));
        refreshToken(loginUser);

        // 保存或更新用户token
        Map<String, Object> map = new HashMap<>();
        map.put("access_token", token);
        map.put("expires_in", expiresIn);
        map.put("type", loginUser.getSysUser().getUserType());
        map.put("nickName", loginUser.getSysUser().getNickName());
        if (SpringUtils.getActiveProfile().equals("dev")) {
            map.put("user_id", loginUser.getUserid());
            map.put("username", loginUser.getUsername());
        }
        return map;
    }


    /**
     * 获取用户身份信息
     *
     * @return 用户信息
     */
    public LoginUser getLoginUser() {
        HttpServletRequest request = ServletUtils.getRequest();
        if (StringUtils.isNull(request)) {
            return null;
        }
        return getLoginUser(request);
    }

    /**
     * 获取用户身份信息
     *
     * @return 用户信息
     */
    public LoginUser getLoginUser(HttpServletRequest request) {
        // 获取请求携带的令牌

        String token = SecurityUtils.getToken(request);
        return getLoginUser(token);
    }

    /**
     * 获取用户身份信息
     *
     * @return 用户信息
     */
    public LoginUser getLoginUser(String token) {
        if (StringUtils.isNotEmpty(token)) {
            String userKey = getTokenKey(token);
            return redisService.getCacheObject(userKey);
        }
        return null;
    }

    /**
     * 设置用户身份信息
     */
    public void setLoginUser(LoginUser loginUser) {
        if (StringUtils.isNotNull(loginUser) && StringUtils.isNotEmpty(loginUser.getToken())) {
            refreshToken(loginUser);
        }
    }

    public void delLoginUser(String token) {
        if (StringUtils.isNotEmpty(token)) {
            String userKey = getTokenKey(token);
            redisService.deleteObject(userKey);
        }
    }

    /**
     * 刷新令牌有效期
     *
     * @param loginUser 登录信息
     */
    public void refreshToken(LoginUser loginUser) {
        loginUser.setLoginTime(System.currentTimeMillis());
        loginUser.setExpireTime(loginUser.getLoginTime() + EXPIRE_TIME * MILLIS_SECOND);
        // 根据uuid将loginUser缓存
        String userKey = getTokenKey(loginUser.getToken());
        redisService.setCacheObject(userKey, loginUser, EXPIRE_TIME, TimeUnit.SECONDS);
    }

    /**
     * 刷新令牌有效期
     *
     * @param token token
     */
    public void refreshToken(String token) {
        LoginUser loginUser = getLoginUser(token);
        if (loginUser != null) {
            loginUser.setLoginTime(System.currentTimeMillis());
            loginUser.setExpireTime(loginUser.getLoginTime() + EXPIRE_TIME * MILLIS_SECOND);
            // 根据uuid将loginUser缓存
            String userKey = getTokenKey(loginUser.getToken());
            redisService.setCacheObject(userKey, loginUser, EXPIRE_TIME, TimeUnit.SECONDS);
        }

    }


    private String getTokenKey(String token) {
        return ACCESS_TOKEN + token;
    }
}
