package net.northking.cctp.element.core.scanner;

import net.northking.cctp.element.core.RegisterInfo;
import net.northking.cctp.element.core.ResourceLoader;
import net.northking.cctp.element.core.annotation.Library;
import net.northking.cctp.element.util.Assert;
import net.northking.cctp.element.validation.Constraint;
import org.slf4j.LoggerFactory;

import java.util.*;

/**
 * ResourceScanner
 *
 * @author fengxiang.zhang
 * @since 1.0
 */
public class ResourceScanner {

    private static org.slf4j.Logger logger = LoggerFactory.getLogger(ResourceScanner.class);
    private ResourceLoader resourceLoader;

    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }

    /**
     * 无组件库定义时，抛出异常
     */
    public LibraryDefinition doScan() throws Exception {
        Class<?> cls = getFactories().iterator().next();
        LibraryDefinition definition = getLibraryDefinition(cls);
        logger.debug("使用{}加载库资源.", resourceLoader.getClassLoader().getClass());
        return definition;
    }

    /**
     * 无组件库时，返回size=0
     */
    public List<LibraryDefinition> doScans() throws Exception {
        Set<Class<?>> clazz = getMultiFactories();
        List<LibraryDefinition> definitions = new ArrayList<>();
        int num = clazz.size();
        logger.info("检测到{}个内置组件库需要加载.", num);
        if (num > 0) {
            logger.debug("使用{}加载规则库资源.", resourceLoader.getClassLoader().getClass());
            for (Class<?> cls : clazz) {
                logger.info("加载组件库->{}", cls);
                definitions.add(getLibraryDefinition(cls));
            }
        }
        return definitions;
    }

    /**
     * @return
     * @throws Exception
     */
    private LibraryDefinition getLibraryDefinition(Class cls) throws Exception {
        Assert.notNull(cls, "组件库入口类不能为空");
        logger.debug("查找Library注解", cls);
        Library an = (Library) cls.getAnnotation(Library.class);
        if (an == null) {
            throw new Exception(String.format("%s必须使用@Library标注.", cls));
        }
        logger.debug("提取@Library信息.", cls);
        String basePackage = an.scanBasePackage();
        Class<? extends RegisterInfo> registerInfoClass = an.infoClass();
        LibraryDefinition definition = new LibraryDefinition();
        definition.setResourceLoader(resourceLoader);
        definition.setLibraryClass(cls);
        logger.debug("创建RegisterInfo实例对象.");
        RegisterInfo registerInfo = registerInfoClass.newInstance();
        logger.debug("库版本号规范检查.");
        Constraint.version(registerInfo.getVersion());
        logger.debug("库类别检查");
        Constraint.isEmpty(registerInfo.getType(),"请确认组件库库类别");
        definition.setRegisterInfo(registerInfo);
        logger.debug("扫描基础包:{}", basePackage);
        definition.setBeanClass(BeanClassLookup.find(resourceLoader, basePackage));
        return definition;
    }

    public Set<Class<?>> getFactories() throws Exception {
        return FactoriesLoader.loadFactories(resourceLoader.getClassLoader());
    }

    public Set<Class<?>> getMultiFactories() throws Exception {
        return FactoriesLoader.loadMultiFactories(resourceLoader.getClassLoader());
    }
}