package com.dayou.interceptor;

import com.dayou.annotation.IgnoreAuth;
import com.dayou.entity.GisUser;
import com.google.common.cache.Cache;
import com.dayou.bo.LoginCacheUserBO;
import com.dayou.constants.JwtConstants;
import com.dayou.exception.BusinessException;
import com.dayou.exception.ErrorCode;
import com.dayou.utils.*;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.text.MessageFormat;

import static com.dayou.common.Constants.GIS_USER;

@Component
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {

    @Autowired
    @Qualifier("loginCache")
    private Cache<Long, LoginCacheUserBO> loginCache;

    @Autowired
    @Qualifier("gisLoginCache")
    private Cache<String, GisUser> gisLoginCache;

    @Autowired
    @Qualifier("noExpireCache")
    private Cache<String, Object> noExpireCache;


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

        boolean ignore = checkIgnore(handler);
        String token = request.getHeader(JwtConstants.REST_TOKEN);
        if (StringUtils.isBlank(token)) {
            token = request.getParameter(JwtConstants.REST_TOKEN);
        }
        if (StringUtils.isBlank(token) && !ignore) {
            ErrorCode.throwBusinessException(ErrorCode.UN_LOGIN);
        }

        LoginCacheUserBO loginCacheUserBO = null;
        try {
            if (StringUtils.isNotBlank(token)) {
                Claims claims = JwtTokenUtil.getClaimFromToken(token, JwtConstants.SECRET);
                String subject = claims.getSubject();
                if (subject.startsWith(GIS_USER)){
                    GisUser gisUser = gisLoginCache.getIfPresent(subject);
                    if (gisUser == null) {
                        ErrorCode.throwBusinessException(ErrorCode.LOGIN_EXPIRE);
                    }
                }else{
                    Long userId = Long.valueOf(subject);
                    loginCacheUserBO = loginCache.getIfPresent(userId);
                    if (loginCacheUserBO == null) {
                        ErrorCode.throwBusinessException(ErrorCode.LOGIN_EXPIRE);
                    }
                    LoginContext.setLoginCacheUserBO(loginCacheUserBO);
                    PermissionContext.setFlag(Boolean.FALSE);
                }
            }
        } catch (ExpiredJwtException ee) {
            //判断token是否过期
            ErrorCode.throwBusinessException(ErrorCode.LOGIN_EXPIRE);
        } catch (Exception e) {
            if (e instanceof BusinessException) {
                throw e;
            }
            log.warn(MessageFormat.format("非法token,token:{0}", token));
            ErrorCode.throwBusinessException(ErrorCode.INVALID_TOKEN);
        }

        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
                                Exception ex) throws Exception {
        LoginContext.removeAll();
        PermissionContext.removeAll();
    }

    private boolean checkIgnore(Object handler) {
        if (handler == null) {
            return true;
        }
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        IgnoreAuth ignoreAuthOnMethod = handlerMethod.getMethodAnnotation(IgnoreAuth.class);
        if (ignoreAuthOnMethod != null) {
            return true;
        }

        Class<?> controllerBean = ((HandlerMethod) handler).getBeanType();
        IgnoreAuth ignoreAuthOnClass = controllerBean.getAnnotation(IgnoreAuth.class);
        if (null != ignoreAuthOnClass) {
            return true;
        }
        return false;
    }
}
