package com.app.framework.core.support.enums.dict.config;

import cn.hutool.core.map.MapUtil;
import com.app.framework.core.support.enums.BaseEnum;
import com.app.framework.core.support.enums.data.EnumItem;
import com.app.framework.core.support.enums.dict.DictEnum;
import com.app.framework.core.support.enums.dict.DictMgt;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.stream.Collectors;

@Component
public class DictEnumConfig implements InitializingBean {

    @Autowired
    private ResourceLoader resourceLoader;
    @Autowired
    private Environment environment;

    private static Map<String, DictMgt> dictMap = new HashMap<>();

    public static Map<String, DictMgt> getDictMap() {
        return dictMap;
    }

    public static DictMgt getDict(String type) {
        return dictMap.get(type);
    }

    public static List<EnumItem> getDictItem(String type) {
        DictMgt dictMgt = getDict(type);
        return dictMgt != null ? dictMgt.getDictItemList() : null;
    }

    @Override
    public void afterPropertiesSet() throws ClassNotFoundException {
        String basePackage = "com.app";
        // 创建scanner
        ClassPathScanningCandidateComponentProvider scanner = getScanner();
        scanner.setResourceLoader(resourceLoader);
        // 设置扫描器scanner扫描的过滤条件
        AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(DictEnum.class);
        scanner.addIncludeFilter(annotationTypeFilter);
        // 通过scanner获取basePackage下的候选类(有标@SimpleRpcClient注解的类)
        Set<BeanDefinition> candidateComponents = scanner.findCandidateComponents(basePackage);
        // 遍历每一个候选类
        for (BeanDefinition candidateComponent : candidateComponents) {
            if (candidateComponent instanceof AnnotatedBeanDefinition) {
                AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) candidateComponent;

                AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
                Map<String, Object> attributes = annotationMetadata.getAnnotationAttributes(DictEnum.class.getCanonicalName());

                final Class<?> cls = Class.forName(beanDefinition.getBeanClassName());
                BaseEnum[] enumConstants = (BaseEnum[]) cls.getEnumConstants();
                List<EnumItem> dictItemList = Arrays.stream(enumConstants).map(e -> {
                    return new EnumItem(e.getValue(), e.getText());
                }).collect(Collectors.toList());

                DictMgt dictMgt = new DictMgt();
                dictMgt.setType(StringUtils.defaultIfBlank(MapUtil.getStr(attributes, "type"), StringUtils.uncapitalize(cls.getSimpleName())));
                dictMgt.setDesc(MapUtil.getStr(attributes, "desc"));
                dictMgt.setDictItemList(dictItemList);
                dictMap.put(dictMgt.getType(), dictMgt);
            }
        }
    }


    /**
     * 创建扫描器
     */
    protected ClassPathScanningCandidateComponentProvider getScanner() {
        return new ClassPathScanningCandidateComponentProvider(false, environment) {
            @Override
            protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
                boolean isCandidate = false;
                if (beanDefinition.getMetadata().isIndependent()) {
                    if (!beanDefinition.getMetadata().isAnnotation()) {
                        isCandidate = true;
                    }
                }
                return isCandidate;
            }
        };
    }

}
