package com.icloud.server.web.shiro.handler;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.ContentType;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;

import com.icloud.server.utils.R;
import com.icloud.server.utils.annotation.AccessRequired;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import org.springframework.beans.factory.annotation.Value;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


/**
 * @description: 请求拦截器
 * @author: zjbing
 * @create: 2021-01-13 14:03
 **/
@Slf4j
@Configuration
public class TokenValidateInterceptor extends HandlerInterceptorAdapter {


    @Autowired
     StringRedisTemplate stringredistemplate;

    @Value("${jwt.key}")
    private String jwtKey;

    // 无需拦截直接访问的地址
    /*@NacosValue(value = "${allow.urls}", autoRefreshed = true)
    private String[] allowUrls;*/

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        // 此处配置的是允许任意域名跨域请求，可根据需求指定
        response.setHeader("Access-Control-Allow-Origin", request.getHeader("origin"));
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS");
        response.setHeader("Access-Control-Max-Age", "86400");
        response.setHeader("Access-Control-Allow-Headers", "*");

        if(HttpMethod.OPTIONS.toString().equals(request.getMethod())) return true;

        // 请求地址
        String requestUri = request.getRequestURI();
        System.out.println("request请求的URL为：" + requestUri);

        log.debug("request请求的URL为：" + requestUri);


        HandlerMethod handlerMethod = (HandlerMethod) handler;

        // 获取类上边的注解, 不需要鉴权的则放行
        AccessRequired controller = AnnotationUtils.findAnnotation(handlerMethod.getBeanType(), AccessRequired.class);

        if (ObjectUtil.isNotNull(controller)) return true;

        // 获取方法上边的注解，不需要鉴权的则放行
        AccessRequired method = AnnotationUtils.findAnnotation(handlerMethod.getMethod(), AccessRequired.class);

        if (ObjectUtil.isNotNull(method)) return true;


        // 判断请求地址是否无需拦击
        /*for (String url : allowUrls) {
            if (StrUtil.containsAnyIgnoreCase(requestUri, url.replaceAll("\\*",""))) {
                return true;
            }
        }*/

        String token = request.getHeader("Token");
        System.out.println("token-------:"+token);

        if (StrUtil.isNotBlank(token)) {

            DecodedJWT decodedJWT = null;

            Long userId = null;
            String tokenId = null;

            try {

                decodedJWT = JWT.require(Algorithm.HMAC256(this.jwtKey)).build().verify(token);
                userId = decodedJWT.getClaim("id").asLong();
                tokenId = decodedJWT.getId();

            } catch (JWTVerificationException e) {

                log.warn("解析Token异常：{}，token={}", e.getMessage(), token);
            }

            if (userId != null) {

                String tokenKey = "token:" + userId + ":" + tokenId;

                Object tokenObject = stringredistemplate.opsForValue().get(tokenKey);

                if (tokenObject != null) {

                    UserToken userToken = JSON.parseObject((String) tokenObject, UserToken.class);

                    if (userToken != null && userToken.getId().equals(decodedJWT.getId()) && userId.equals(userToken.getUserId())) {

                        // 此时Token是合法的Token，需要进行续约操作
                        /*String userTokenStr = JSON.toJSONString(userToken);
                        redisService.setex(tokenKey, userTokenStr, userToken.isRemember()
                                ? TimeUnit.DAYS.toSeconds(7)
                                : TimeUnit.MINUTES.toSeconds(30));*/

                        // 把当前会话信息保存到当前请求的threadlocal
                        LoginInfoThreadLocal.setContext(userToken);

                        return true;
                    }
                } else {

                    //throw new RuntimeException("Token不存在/非法的Token/Token已过期");
                    response.setContentType(ContentType.JSON.toString());
                    response.setStatus(HttpStatus.UNAUTHORIZED.value());
                    response.getWriter().print(JSONUtil.toJsonStr(R.failed(401,"Invalid token")));

                    return false;
                }
            }
        }

        //throw new RuntimeException("Token不存在/非法的Token/Token已过期");
        response.setContentType(ContentType.JSON.toString());
        response.setStatus(HttpStatus.UNAUTHORIZED.value());
        response.getWriter().print(JSONUtil.toJsonStr(R.failed(401,"Invalid token")));

        return false;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        //清掉当前线程缓存会话信息
        LoginInfoThreadLocal.clear();
    }
}

