package com.sunxung.factoring.component.util;


import com.alibaba.fastjson.JSONObject;
import com.auth0.jwt.interfaces.Claim;
import com.sunxung.factoring.component.cache.RedisCache;
import com.sunxung.factoring.component.constance.JwtTokenConstant;
import com.sunxung.factoring.component.enums.ClientTypeEnum;
import com.sunxung.factoring.entity.sys.User;
import com.sunxung.factoring.service.sys.dto.SessionDto;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.Arrays;
import java.util.List;
import java.util.Map;


/**
 * 主要是操作redis 缓存 用户的 token
 *
 * @author 张超
 * @date 2021/3/10
 */
@Component
public class TokenAndSessionCacheUtil {

  public static final String TOKEN_PREFIX = "token:";
  private static final String SESSION_PREFIX = "session:";
  public static final String REDIS_SPLIT_MARK = ":";
  private static final String TOKEN_DESTORY = "tokenDescory:";

  private static final Integer DEFAULT_EXPIRATION = 60 * 60 * 2; //单位秒

  @Autowired
  RedisCache redisCache;

  /**
   * 缓存 token -> user 的关系
   *
   * @param clientType
   * @param token
   * @param loginUser
   */
  public void token2User(String clientType, String token, User loginUser) {

    String key = tokenKey(clientType, token);
    //redisTemplate.opsForValue().set(key, loginUser);//, DEFAULT_EXPIRATION, TimeUnit.SECONDS);
    redisCache.setForString(key,loginUser,600*30);
  }


  public void removeTokenUser(String token) {
    //从token 中解析出 用户类型
    Map<String, Claim> claims = JwtHS256Util.getClaims(token);
    String clientType = claims.get(JwtTokenConstant.CLIENT_TYPE).asString();

    String key = tokenKey(clientType, token);
    redisCache.remove(key);
  }


  /**
   * 获取 loginUser  通过token
   *
   * @param token
   * @return
   */
  public User getLoginUserByToken(String token) {
    //从token 中解析出 用户类型
    Map<String, Claim> claims = JwtHS256Util.getClaims(token);

    String clientType = claims.get(JwtTokenConstant.CLIENT_TYPE).asString();
    String tokenKey = tokenKey(clientType, token);
//    JSONObject obj = (JSONObject) redisTemplate.opsForValue().get(tokenKey);
//    if (obj != null) {
//      UserDTO abstractUser = JSONObject.toJavaObject(obj, UserDTO.class);
//      return abstractUser;
//    }
    String o = redisCache.getForString(tokenKey);
    if(o!=null){
      //同时给该用户 续期
      redisCache.updateTime(tokenKey,60*30);
      return JSONObject.parseObject(o,User.class);
    }
    return null;
  }

  /**
   * 保存了 userId-->该用户在app/web 上的登陆状态   map 中的key  web/app
   *
   * @param baseUser
   * @param clientType
   * @param value
   */
  public void setSeeison(User baseUser, String clientType, SessionDto value) {
    if (baseUser.getId() == null) {
      return;
    }
    String key = sessionKey(baseUser.getId(), baseUser.getLoginName());
    //session 不加过期时间  采用了监听器 监听token 过期  然后触发session删除
    //redisTemplate.opsForHash().put(key, clientType, value);
    redisCache.setForHash(key,clientType,value);
  }

  /**
   * 获取 Map<Object,Object>
   *
   * @return
   */
  public SessionDto getSession(User baseUser, String clientType) {
    if (baseUser.getId() == null) {
      return null;
    }
    SessionDto sessionDTO = null;
    String key = sessionKey(baseUser.getId(), baseUser.getLoginName());
    Object forHash = redisCache.getForHash(key, clientType, SessionDto.class);
    if (forHash != null) {
        sessionDTO = (SessionDto) forHash;
    }
    return sessionDTO;
  }

  /**
   * 删除其中一种 终端的token
   */
  public void removeSessionOneType(Long userId, String clientType, String account) {
    String key = sessionKey(userId, account);
    redisCache.removeForHash(key,clientType);
  }

//  /**
//   * 删除session
//   *
//   * @param userId
//   */
//  public void removeSession(String userType, Long userId) {
//    if (userId == null) {
//      return;
//    }
//    String key = sessionKey(userType, userId);
//    TedisUtil.delete(key);
//  }

  /**
   * 获取token 中的 用户类型
   */
//  public String getUserType(String token) {
//    JWTClaimsSet claims = JwtHS256Util.getClaims(token);
//    String userType = claims.getStringClaim(JwtTokenConstant.USER_TYPE);
//    return userType;
//  }


  /**
   * 获取用户中的 客户端类型
   *
   * @param token
   * @return
   */
  public String getClientType(String token) {
    Map<String, Claim> claims = JwtHS256Util.getClaims(token);
    String clientType = claims.get(JwtTokenConstant.CLIENT_TYPE).asString();

    return clientType;
  }


  /**
   * 获取用户id
   *
   * @param token
   * @return
   */
  public Long getUserId(String token) {
    Map<String, Claim> claims = JwtHS256Util.getClaims(token);
    Long userId = claims.get(JwtTokenConstant.USER_ID).asLong();

    return userId;
  }


  /**
   * 清空所有信息  session  和 token    app和web
   *
   * @param token
   */
  public void clear(String token) {


    Map<String, Claim> claims = JwtHS256Util.getClaims(token);
    String account = claims.get(JwtTokenConstant.ACCOUNT).asString();
    Long userId = claims.get(JwtTokenConstant.USER_ID).asLong();

    String sessionKey = sessionKey(userId, account);
    String appTokenKey = tokenKey(ClientTypeEnum.APP.getCode(), token);
    String webTokenKey = tokenKey(ClientTypeEnum.WEB.getCode(), token);
    String weChatTokenKey = tokenKey(ClientTypeEnum.WECHAT.getCode(), token);
    List<String> keys = Arrays.asList(sessionKey, appTokenKey, webTokenKey, weChatTokenKey);

    //TODO


  }

//  /**
//   * 设置token非自然消亡标记
//   *
//   * @param phone
//   */
//  public void setTokenAbnormalDestoryFlag(String phone,
//      AbnormalDestoryTypeEnum abnormalDestoryType) {
//    String key = tokenDestoryKey(phone);
//    redisTemplate.opsForValue().set(key, abnormalDestoryType.getType(), 300, TimeUnit.SECONDS);
//  }

  /**
   * @return
   */
  public void destoryToken(Long userId, List<String> accounts) {
    if (!CollectionUtils.isEmpty(accounts)) {
      for (String account : accounts) {
        String sessionKey = sessionKey(userId, account);
        for (ClientTypeEnum c : ClientTypeEnum.values()) {
//          JSONObject obj = (JSONObject) redisTemplate.opsForHash().get(sessionKey, c.getCode());
//          if (obj != null) {
//            SessionDTO dto = JSONObject.toJavaObject(obj, SessionDTO.class);
//            this.removeTokenUser(dto.getToken());
//          }
          Object forHash = redisCache.getForHash(sessionKey, c.getCode(), SessionDto.class);
          if(forHash!=null){
            SessionDto dto = (SessionDto)forHash;
            this.removeTokenUser(dto.getToken());
          }
        }
      }
    }
  }

//  /**
//   * 获取是否存在
//   *
//   * @param userType
//   * @param phone
//   * @return
//   */
//  public String getTokenAbnormalDestoryFlag(String userType, String phone) {
//    String key = tokenDestoryKey(phone);
//    String abnormalDestoryType = (String) redisTemplate.opsForValue().get(key);
//    if (!StringUtils.isEmpty(abnormalDestoryType)) {
//      redisTemplate.delete(key);
//    }
//    return abnormalDestoryType;
//  }


  /**
   * key = session前缀+用户id
   *
   * @param userId
   * @return
   */
  private String sessionKey(Long userId, String account) {
    StringBuffer sb = new StringBuffer();
    sb.append(SESSION_PREFIX)
        .append(userId)
        .append(REDIS_SPLIT_MARK)
        .append(account);
    return sb.toString();

  }

  /**
   * key =  token前缀  + 客户端类型 + 分隔符 + token
   *
   * @param clientType
   * @param token
   * @return
   */
  private String tokenKey(String clientType, String token) {
    StringBuffer sb = new StringBuffer();
    sb.append(TOKEN_PREFIX)
        .append(clientType)
        .append(REDIS_SPLIT_MARK)
        .append(token);

    return sb.toString();
  }

  /**
   * 创建token消亡的提示语
   *
   * @param username
   * @return
   */
  private String tokenDestoryKey(String username) {
    StringBuffer sb = new StringBuffer();
    sb.append(TOKEN_DESTORY)
        .append(username);
    return sb.toString();
  }

}
