package com.philisense.www.web;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.philisense.www.api.processor.VcodeProcessorFactory;
import com.philisense.www.core.text.Convert;
import com.philisense.www.enums.VcodeType;
import com.philisense.www.exception.UtilsException;
import com.philisense.www.properties.VcodeProperties;
import com.philisense.www.utils.ServletUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

@Component
public class VcodeFilter extends OncePerRequestFilter {
    private static final Logger log = LoggerFactory.getLogger(VcodeFilter.class);

    @Resource
    private VcodeProcessorFactory vcodeProcessorFactory;

    @Resource
    private VcodeProperties vcodeProperties;

    @Resource
    private ObjectMapper objectMapper;

    private final AntPathMatcher pathMatcher = new AntPathMatcher();

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
        String type = parseVcodeType(request);
        if (StringUtils.isNotEmpty(type)) {
            log.info("vcode filter urls: {}", vcodeProperties.getFilterUrls());
            String typeIn = request.getParameter("vcodeType");
            if (StringUtils.isNotEmpty(typeIn) && !typeIn.equals(type)) {
                handlerErrorResponse(response, String.format("前端提交的验证类型为%s，而后台配置为%s", typeIn, type), null);
                return;
            }
            VcodeType vcodeType = VcodeType.get(type);
            if (vcodeType == null) {
                handlerErrorResponse(response,"系统不支持该校验码类型：" + type, null);
                return;
            }
            try {
                vcodeProcessorFactory.get(vcodeType).doValidate(new ServletWebRequest(request, response));
            } catch (UtilsException ex) {
                log.error(ex.getMessage(), ex);
                handlerErrorResponse(response,ex.getMessage(), Convert.toStr(ex.getStatus()));
                return;
            }
            log.info("放行：url = {}, vcodeType = {}", request.getRequestURL(), type);
        }

        chain.doFilter(request, response);
    }

    /**
     * 过滤要进行校验码验证的请求url
     * @param request
     * @return
     */
    private String parseVcodeType(HttpServletRequest request) {
        /*String url = request.getRequestURI().replace(request.getContextPath(), "");
        Map<String, String> grantMap = vcodeProperties.getOauthGrant();
        if ("/oauth/token".equals(url)) {
            String grantType = request.getParameter("grant_type");
            return grantMap.get(grantType);
        }
        Map<String, String> urlMap = vcodeProperties.getFilterUrls();
        for (Map.Entry<String, String> entry : urlMap.entrySet()) {
            if (pathMatcher.match(entry.getKey(), url)) {
                return entry.getValue();
            }
        }
        return null;*/
        return request.getParameter("vcodeType");
    }

    private void handlerErrorResponse(HttpServletResponse response, String message, String errCode) throws IOException {
        log.error(message);
        Map<String, Object> errMap = new HashMap<>();
        errMap.put("success", false);
        errMap.put("message", message);
        if (StringUtils.isNotEmpty(errCode)) {
            errMap.put("status", errCode);
        }
        ServletUtils.renderString(response, objectMapper.writeValueAsString(errMap));
    }
}
