package com.wx.application.filter;

import java.io.IOException;
import java.util.UUID;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

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.HttpMethod;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.context.support.SpringBeanAutowiringSupport;

import com.alibaba.fastjson.JSON;
import com.wx.application.base.BaseController;
import com.wx.application.base.ErrorCodeEnum;
import com.wx.application.base.ResponseData;
import com.wx.application.configuration.FilterIgnorePropertiesConfig;
import com.wx.application.constant.CONSTANT;
import com.wx.application.util.JwtUtils;

/**
 * jwt 拦截过滤器
 *
 * @comment
 */
@WebFilter(filterName = "jwtFilter", urlPatterns = "/*")
@Order(2)
//@Slf4j
public class JwtAuthFilter extends BaseController implements Filter {
    @Autowired
    private FilterIgnorePropertiesConfig ignores;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this,
                filterConfig.getServletContext());

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;

        String uri = httpRequest.getRequestURI();
        String token = httpRequest.getHeader(CONSTANT.TOKEN_NAME);

        requestInitialized(httpRequest);

        ResponseData errorMsg = null;

        try {
            if (matchIgnore(uri)) {
                chain.doFilter(request, response);
                return;
            } else if (HttpMethod.OPTIONS.name().equals(httpRequest.getMethod())) {
                httpResponse.setStatus(HttpServletResponse.SC_OK);
                chain.doFilter(request, response);
                return;
            } else {
                if (StringUtils.isEmpty(token)) {
                    errorMsg = error(ErrorCodeEnum.UNAUTHORIZED);
                    return;
                }
                //检查jwt有效性
                if (!JwtUtils.checkTokenExpired(token)) {
                    errorMsg = error(ErrorCodeEnum.AUTHORIZATION_EXPIRED);
                    return;
                }
                chain.doFilter(request, response);
                return;
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            if (null != errorMsg) {
                errorMsg.setRequestId(MDC.get(CONSTANT.REQUEST_ID_KEY));
                httpResponse.setContentType("application/json;charset=utf-8");
                httpResponse.getWriter().write(JSON.toJSONString(errorMsg));
            }
        }
    }

    @Override
    public void destroy() {
    }

    /**
     * 初始化request 记录全局唯一的标识
     */
    public void requestInitialized(HttpServletRequest request) {
        String requestId = null;
        if (request != null) {
            requestId = request.getHeader(CONSTANT.X_REQ_ID);
        }
        if (org.apache.commons.lang.StringUtils.isBlank(requestId)) {
            requestId = UUID.randomUUID().toString();
        }
        MDC.put(CONSTANT.REQUEST_ID_KEY, requestId);
        MDC.put(CONSTANT.REQUEST_URL, request.getRequestURI());
    }

    private boolean matchIgnore(String uri) {
        AntPathMatcher pm = new AntPathMatcher();
        boolean match = ignores.getUrls().stream().anyMatch(v -> pm.match(v, uri));
        return match;
    }
}
