package com.ruoyi.framework.interceptor;

import cn.hutool.core.util.ObjectUtil;
import com.ruoyi.common.constant.Constants;

import com.ruoyi.common.enums.ExceptionEnum;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.framework.web.service.ApiTokenService;
import com.ruoyi.user.domain.User;
import com.ruoyi.user.service.IUserService;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.MalformedJwtException;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;

/**
 * 登录拦截器  拦截小程序接口
 */
@Component
public class LoginApiInterceptor implements HandlerInterceptor {

    @Resource
    private ApiTokenService apiTokenService;

    @Resource
    private IUserService userService;


    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 判断是否存在令牌信息，如果存在，则允许登录
        //token_access 这就是前端放在请求头中的jwtToken
        String accessToken = request.getHeader(Constants.API_TOKEN);
        if (ObjectUtil.isEmpty(accessToken)) {
            //这里抛给前端的为一个自定义异常枚举，可自己定义
//            throw new ServiceException(ExceptionEnum.USER_NOT_LOGIN);
            return true;
        }
        try {
            Claims claims = apiTokenService.getAllClaimsFromToken(accessToken);

            //通过jwt加密工具中自定义参数取出自己想要验证的值，来进行操作
            long tid = Long.parseLong(claims.get(Constants.USER_ID).toString());
            User user = userService.getById(tid, false);
            if (ObjectUtil.isNull(user)) {
                throw new ServiceException(ExceptionEnum.USER_NOT_EXISTS);
            }
            //如果用户被禁用，则不能登录
            if (!user.getStatus()) {
                throw new ServiceException(ExceptionEnum.USER_DISABLED);
            }

            // TODO user需要加上扩展信息
            //这个可要可不要，通过这里自己在请求中加参数，可以让前端少传几个已经在token中自定义好的值
            UserContext.setUser(user);
//            request.setAttribute(Constants.TEACHER_ID, Long.toString(tid));

            //接下来可处理需要验证并且已经通过后的业务
            //即将过期，则刷新token
            Date expirationDateFromToken = apiTokenService.getExpirationDateFromToken(accessToken);

            if (apiTokenService.isRefreshToken(expirationDateFromToken)) {
                //刷新token，并返回
                String token = apiTokenService.generateToken(user);
                response.setHeader(Constants.REFRESH_TOKEN, token);
            }

        } catch (ExpiredJwtException e) {
            throw new ServiceException(ExceptionEnum.TOKEN_EXPIRED);
        } catch (MalformedJwtException e) {
            throw new ServiceException(ExceptionEnum.TOKEN_ERROR);
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView
        modelAndView) {
        UserContext.close();
    }
}
