package com.topsunit.query.spring.mapper;

import com.huigou.data.query.executor.SQLExecutorDao;
import com.topsunit.query.annotations.Mapper;
import com.topsunit.query.binding.MapperProxyFactory;
import io.github.classgraph.ClassGraph;
import io.github.classgraph.Resource;
import io.github.classgraph.ScanResult;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.FactoryBean;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;

/**
 * @param <T>
 * @author yonghuan
 */
public class MapperFactoryBean<T> implements FactoryBean<T> {

    private final static String MAPPER_SUFFIX = "Mapper";
    private final static int MAPPER_SUFFIX_LENGTH = MAPPER_SUFFIX.length();
    private SQLExecutorDao sqlExecutor;
    private Class<T> mapperInterface;

    public MapperFactoryBean() {
    }

    public MapperFactoryBean(Class<T> mapperInterface) {
        this.mapperInterface = mapperInterface;
    }

    public SQLExecutorDao getSqlExecutor() {
        return sqlExecutor;
    }

    public void setSqlExecutor(SQLExecutorDao sqlExecutor) {
        this.sqlExecutor = sqlExecutor;
    }

    public Class<T> getMapperInterface() {
        return mapperInterface;
    }

    public void setMapperInterface(Class<T> mapperInterface) {
        this.mapperInterface = mapperInterface;
    }

    @Override
    public T getObject() throws Exception {
        Mapper mapper = mapperInterface.getAnnotation(Mapper.class);
        String xml = mapper.xml();
        if (StringUtils.isBlank(xml)) {
            // 未指定查询xml文件，将自定匹配
            String interfaceName = mapperInterface.getSimpleName();
            interfaceName = Character.toLowerCase(interfaceName.charAt(0)) + interfaceName.substring(1);
            List<String> mapperXmlPatterns = new ArrayList<>(2);
            mapperXmlPatterns.add(String.join(".", interfaceName, "xml"));
            if (interfaceName.endsWith(MAPPER_SUFFIX)) {
                String name = interfaceName.substring(0, interfaceName.length() - MAPPER_SUFFIX_LENGTH);
                mapperXmlPatterns.add(name + ".xml");
            }
            xml = mapperXmlPatterns.stream()
                    .map(this::findMapperXml)
                    .filter(Optional::isPresent)
                    .map(Optional::get)
                    .findFirst()
                    .orElseThrow(() -> new IllegalArgumentException(String.format("无法匹配查询xml文件 %s", mapperInterface.getSimpleName())));
        }
        MapperProxyFactory<T> factory = new MapperProxyFactory<>(mapperInterface, xml, sqlExecutor);
        return factory.newInstance();
    }

    private Optional<String> findMapperXml(String file) {
        try (ScanResult scanResult = new ClassGraph().scan()) {
            return scanResult.getResourcesWithExtension("xml").stream()
                    .map(Resource::getPath)
                    .filter(f -> f.endsWith(file))
                    .sorted(Comparator.comparing(String::length).reversed())
                    .findFirst();
        }
    }

    @Override
    public Class<?> getObjectType() {
        return mapperInterface;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }
}
