package com.jy.framework.handler;

import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.jy.framework.config.JyConfig;
import com.jy.framework.model.bo.PathInfoBo;
import jakarta.annotation.Resource;
import lombok.Getter;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.condition.PathPatternsRequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

@Component
public class AllPathHandler implements InitializingBean {

    /**
     * 路径匹配器
     */
    private static final AntPathMatcher antPathMatcher = new AntPathMatcher(StringPool.BACK_SLASH);

    /**
     * 所有请求方法
     */
    private static final Set<String> ALL_METHOD_SET = Arrays.stream(RequestMethod.values()).map(Enum::name).collect(Collectors.toSet());

    /**
     * 排除的路径
     */
    private static final Set<String> EXCLUDE_PATH_SET = new HashSet<>() {{
        add("/error");
        add("/getLoginInfo");
        add("/getUserInfo");
        add("/editUserInfo");
        add("/editPwd");
    }};

    @Getter
    private final List<PathInfoBo> pathInfoList = new ArrayList<>();

    @Resource
    private RequestMappingHandlerMapping requestMappingHandlerMapping;

    @Resource
    private JyConfig jyConfig;

    @Override
    public void afterPropertiesSet() {
        Map<RequestMappingInfo, HandlerMethod> map = requestMappingHandlerMapping.getHandlerMethods();
        map.keySet().forEach(this::processPathPatterns);
        pathInfoList.sort(Comparator.comparing(PathInfoBo::getBestMatching));
    }

    private void processPathPatterns(RequestMappingInfo requestMappingInfo) {
        PathPatternsRequestCondition pathPatternsCondition = requestMappingInfo.getPathPatternsCondition();
        if (pathPatternsCondition == null) {
            return;
        }

        pathPatternsCondition.getPatterns().forEach(pattern -> {

            // 匹配路径
            String patternString = pattern.getPatternString();

            // 开放接口无需鉴权
            for (String openUrl : jyConfig.getOpenUrl()) {
                if (antPathMatcher.match(openUrl, patternString)) {
                    return;
                }
            }

            // 排除指定无需鉴权接口
            if (EXCLUDE_PATH_SET.contains(patternString)) {
                return;
            }

            PathInfoBo pathInfoBo = new PathInfoBo();
            pathInfoBo.setBestMatching(patternString);

            Set<RequestMethod> methods = requestMappingInfo.getMethodsCondition().getMethods();
            if (methods.isEmpty()) {
                pathInfoBo.setMethodSet(ALL_METHOD_SET);
            } else {
                pathInfoBo.setMethodSet(methods.stream().map(Enum::name).collect(Collectors.toSet()));
            }

            pathInfoList.add(pathInfoBo);
        });

    }

}
