package com.jeeplus.common;

import cn.hutool.extra.spring.SpringUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.jeeplus.common.constant.ErrorConstants;
import com.jeeplus.common.utils.RequestUtils;
import com.jeeplus.config.properties.JeePlusProperties;
import com.jeeplus.sys.feign.IUserApi;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;

@Slf4j
@Component
public class TokenProvider {
    public static final String TOKEN = "token";

    public static final String SIGN_CODE = "@#&#$^JWE@#$F123";

    /**
     * 校验token是否正确
     *
     * @param token 密钥
     * @return 是否正确
     */
    public static boolean validateToken(String token) {
        try {
            String userName = TokenProvider.getLoginName ( token );
            Algorithm algorithm = Algorithm.HMAC256 ( SIGN_CODE );
            JWTVerifier verifier = JWT.require ( algorithm )
                    .withClaim ( "username", userName )
                    .build ( );
            verifier.verify ( token );
            return true;
        } catch (TokenExpiredException e) {
            log.error ( ErrorConstants.LOGIN_ERROR_EXPIRED );
        } catch (Exception e) {
            log.error ( ErrorConstants.LOGIN_ERROR_INCORRECT );
        }
        return false;

    }

    /**
     * 获得token中的信息无需secret解密也能获得
     *
     * @return token中包含的用户名
     */
    public static String getLoginName(String token) {
        try {
            DecodedJWT jwt = JWT.decode ( token );
            return jwt.getClaim ( "username" ).asString ( );
        } catch (Exception e) {
            return null;
        }
    }


    /**
     * 生成签名
     *
     * @param username 用户名
     * @return 加密的token
     */
    public static String createAccessToken(String username) {
        Date date = new Date ( System.currentTimeMillis ( ) + JeePlusProperties.newInstance ( ).getEXPIRE_TIME ( ) );
        Algorithm algorithm = Algorithm.HMAC256 ( SIGN_CODE );
        // 附带username信息
        return JWT.create ( )
                .withClaim ( "username", username )
                .withExpiresAt ( date )
                .sign ( algorithm );
    }


    public static Authentication getAuthentication(String token) {
        DecodedJWT jwt = JWT.decode ( token );
        String username = jwt.getClaim ( "username" ).asString ( );

        // 权限集合
        List <GrantedAuthority> authorities = new ArrayList <> ( );
        // 得到用户角色
        String userName = TokenProvider.getLoginName ( token );
        Set <String> permissions = SpringUtil.getBean ( IUserApi.class ).getPermissions ( userName );
        // 添加基于Permission的权限信息
        for (String permission : permissions) {
            authorities.add ( new SimpleGrantedAuthority ( permission ) );
        }

        org.springframework.security.core.userdetails.User principal = new org.springframework.security.core.userdetails.User ( username, "", authorities );

        return new UsernamePasswordAuthenticationToken ( principal, token, authorities );
    }

    /**
     * 获取token，支持三种方式, 请求参数、header、cookie， 优先级依次降低，以请求参数中的优先级最高。
     *
     * @param httpServletRequest
     * @return
     */
    public static String resolveToken(HttpServletRequest httpServletRequest) {
        return RequestUtils.resolveToken ( httpServletRequest, TokenProvider.TOKEN );
    }

    public static String getCurrentToken() {
        return resolveToken ( RequestUtils.getRequest ( ) );
    }

}
