package com.cool.store.config;

import com.alibaba.fastjson.JSON;
import com.cool.store.constants.CommonConstants;
import com.cool.store.enums.ErrorCodeEnum;
import com.cool.store.response.ResponseResult;
import com.cool.store.context.CurrentUserHolder;
import com.cool.store.utils.RedisUtilPool;
import com.cool.store.context.LoginUserInfo;
import com.cool.store.utils.UUIDUtils;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.List;
import java.util.Objects;

/**
 * @author ydw
 * @Description 权限校验
 * @date 2020/1/15
 */
@Component
@Order(3)
@Slf4j
public class TokenValidateFilter implements Filter {

    @Autowired
    private RedisUtilPool redisUtilPool;

    private static AntPathMatcher matcher = new AntPathMatcher();

    private static List<String> patternList =

            Lists.newArrayList("/web/check/ok","/check/ok",
                    "/zxjp/doc.html","/zxjp/v2/api-docs","/zxjp/favicon.ico","/**/test/**","/zxjp/pc/feiShuLogin","/zxjp/pc/oss/getUploadFileConfig",
                    "/**/swagger*/**", "/**/webjars/**",
                    //腾讯音视频回调，单独做验签
                    "/zxjp/pc/video/**",
                    "/zxjp/pc/vod/callback",
                    "/zxjp/pc/sysRole/**",
                    "/zxjp/**/api/audit/result",
                    "/zxjp/pc/video/**",
                    "/zxjp/**/api/license"


            );

    /**
     * @param uri
     * @return boolean
     * @throws
     * @Title excludePath
     * @Description 是否是放行的请求
     */
    private boolean excludePath(String uri) {
        for (String pattern : patternList) {
            if (matcher.match(pattern, uri)) {
                return true;
            }
        }
        return false;
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        //do nothing
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest reqs = (HttpServletRequest) servletRequest;
        String uri = reqs.getRequestURI();
        if(uri.startsWith("/zxjp/mini")){
            filterChain.doFilter(servletRequest, servletResponse);
            return;
        }
        MDC.put(CommonConstants.REQUEST_ID, UUIDUtils.get32UUID());
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        String method = reqs.getMethod();
        String userStr = "";
        LoginUserInfo currentUser = null;
        boolean isInWhiteList = excludePath(uri);
        String accessToken = reqs.getHeader("accessToken");
        String key = MessageFormat.format(CommonConstants.ACCESS_TOKEN_KEY, accessToken);
        if(StringUtils.isNotBlank(accessToken)){
            userStr = redisUtilPool.getString(key);
            if(StringUtils.isNotBlank(userStr)){
                currentUser = JSON.parseObject(userStr, LoginUserInfo.class);
            }
        }
        log.info("url:{}, method:{}", uri, method);
        if ( !isInWhiteList && !method.equals("OPTIONS")) {
            if (StringUtils.isEmpty(accessToken)) {
                response.setStatus(HttpStatus.OK.value());
                response.getWriter().write(JSON.toJSONString(
                        ResponseResult.fail(ErrorCodeEnum.ACCESS_TOKEN_INVALID)));
                return;
            }
            if (Objects.isNull(currentUser)) {
                response.setStatus(HttpStatus.OK.value());
                response.getWriter().write(JSON.toJSONString(
                        ResponseResult.fail(ErrorCodeEnum.ACCESS_TOKEN_INVALID)));
                return;
            }
            log.info("access_token:{}, userId:{}, username:{}", accessToken, currentUser.getUserId(), currentUser.getName());
        }
        if(StringUtils.isBlank(userStr) && !isInWhiteList){
            response.setStatus(HttpStatus.OK.value());
            response.getWriter().write(JSON.toJSONString(
                    ResponseResult.fail(ErrorCodeEnum.ACCESS_TOKEN_INVALID)));
            return;
        }
        try {
            CurrentUserHolder.setUser(userStr);
            filterChain.doFilter(servletRequest, servletResponse);
        } finally {
            CurrentUserHolder.removeUser();
            MDC.clear();
        }
    }

    @Override
    public void destroy() {
        //do nothing
    }
}
