package com.backendsys.modules.common.config.security.annotations;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import com.backendsys.modules.common.config.security.annotations.Anonymous;
import org.apache.commons.lang3.RegExUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import cn.hutool.core.util.ReUtil;

// 编辑注释权限
// src/main/java/com/backendsys/modules/common/config/security/filter/JwtAuthenticationFilter.java
@Configuration
public class AnonymousProperties implements InitializingBean, ApplicationContextAware {

    private static final Pattern PATTERN = Pattern.compile("\\{(.*?)\\}");
    private ApplicationContext applicationContext;
    private List<String> urls = new ArrayList<>();
    public String ASTERISK = "*";

    @Override
    public void afterPropertiesSet() throws Exception {

//        System.out.println("afterPropertiesSet:");

        // 将整个项目所有的bean对象都拿出来
        RequestMappingHandlerMapping mapping = applicationContext.getBean(RequestMappingHandlerMapping.class);
        // 获取每一个方法，获取url和类与方法对应的信息
        Map<RequestMappingInfo, HandlerMethod> map = mapping.getHandlerMethods();

        // info代表每一个url对象
        map.keySet().forEach(info -> {
//          获取类和方法
            HandlerMethod handlerMethod = map.get(info);

            // 获取方法上边的注解 替代path variable 为 *
//            AnnotationUtils.findAnnotation()为第三方的依赖，进行判断 一个方法上有没有注解
            Anonymous method = AnnotationUtils.findAnnotation(handlerMethod.getMethod(), Anonymous.class);

            if (method != null) {
//                Pattern pattern = Pattern.compile("\\{(\\w+) \\[(.+?)\\]}");
//                // 排除 SSE协议接口 多余的字段
//                String infoContent = info.toString().replace(", produces [text/event-stream]", "");
//                Matcher matcher = pattern.matcher(infoContent);
////                System.out.println("matcher1:");
////                System.out.println(matcher);
////                Matcher matcher = pattern.matcher(info.toString());
//                if (matcher.find()) {
//                    String url = matcher.group(2);
//                    System.out.println("url: " + url);
//                    urls.add(url);
//                }

                // 正则表达式，匹配第一个方括号内的内容
                Pattern regex = Pattern.compile("\\[(.*?)\\]");
                String url = ReUtil.getGroup1(regex, info.toString());
                if (StrUtil.isNotEmpty(url)) {
                    // System.out.println("(@Anonymous) url: " + url);
                    urls.add(url);
                }

            }

////          ifPresent()方法就是会返回一个boolean类型值，如果对象不为空则为真，如果为空则为false
//            Optional.ofNullable(method).ifPresent(anonymous ->
//                //获取url的Set集合，一个方法可能对应多个url
//                info.getPatternsCondition().getPatterns()
//                    .forEach(
//                        url -> urls.add(RegExUtils.replaceAll(String.valueOf(url), PATTERN, ASTERISK))
//                    ));

            // 获取类上边的注解, 替代path variable 为 *
            Anonymous controller = AnnotationUtils.findAnnotation(handlerMethod.getBeanType(), Anonymous.class);
            Optional.ofNullable(controller).ifPresent(anonymous -> info.getPatternsCondition().getPatterns()
                .forEach(url -> urls.add(RegExUtils.replaceAll(String.valueOf(url), PATTERN, ASTERISK))));
        });

    }



    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    public List<String> getUrlsList() {
        return urls;
    }

    public String[] getUrls() {
        return Convert.toStrArray(urls);
    }


    public void setUrls(List<String> urls)
    {
        this.urls = urls;
    }

}
