package com.xingxi.api.configuration;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.config.WxMaConfig;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.xingxi.api.common.ResponseDTO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

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.Arrays;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


@Slf4j
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
@RequiredArgsConstructor
class AttachRequestIdRequestFilter extends OncePerRequestFilter {

    private final RequestMatcher requestMatcher = new AntPathRequestMatcher("/api/store/**");
    private final ObjectMapper objectMapper;
    private final WxMaService maService;

    @Value("${spring.application.request.referers}")
    private String[] referers;


    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String uuid = UUID.randomUUID().toString();


        if (requestMatcher.matches(request)) {

            String userAgent = request.getHeader("User-Agent");
            if (!(userAgent != null && userAgent.contains("MicroMessenger"))) {
                log.debug("User-Agent[" + userAgent + "],请使用微信浏览器");
                responseFail(uuid, response);
                return;
            }

            String referer = request.getHeader("Referer");
            if (!((referer != null && verifyReferer(referer)) || othersReferer(referer))) {
                log.debug("Referer[" + referer + "]错误,请求不是来自微信服务器");
                responseFail(uuid, response);
                return;
            }

        }

        ContentCachingRequestWrapper cachingRequestWrapper = new ContentCachingRequestWrapper(request);
        String requestIdKey = "X-REQUEST-ID";

        try {
            cachingRequestWrapper.setAttribute(requestIdKey, uuid);
            MDC.put(requestIdKey, uuid);
            filterChain.doFilter(cachingRequestWrapper, response);
        } finally {
            MDC.remove(requestIdKey);
        }


    }


    private void responseFail(String requestId, HttpServletResponse response) {
        ResponseDTO<Void> responseDTO = new ResponseDTO<>(500);
        responseDTO.setRequestId(requestId);
        responseDTO.setMessage("拒绝访问");
        response.setStatus(500);
        response.setCharacterEncoding("utf-8");
        try {
            response.getWriter().write(objectMapper.writeValueAsString(responseDTO));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    private boolean othersReferer(String referer){
        return Arrays.stream(referers).anyMatch(referer::contains);
    }

    private boolean verifyReferer(String referer) {
        WxMaConfig wxMaConfig = maService.getWxMaConfig();
        String appid = wxMaConfig.getAppid();
        String regEx = String.format("^https://servicewechat.com/%s/([a-zA-Z0-9.]{1,}|devtools)/page-frame.html$", appid);
        Pattern pattern = Pattern.compile(regEx);
        Matcher matcher = pattern.matcher(referer);
        return matcher.matches();
    }


}
