package cd.casic.plugin.core.register.mybatis;

import cd.casic.plugin.dataobject.pojo.PluginInfo;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.mapper.MapperFactoryBean;
import org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.annotation.*;

import java.util.ArrayList;
import java.util.List;

/**
 * @description: TODO
 * @author: mianbin
 * @date: 2025/5/22 19:49
 * @version: 1.0
 */
@Slf4j
@NoArgsConstructor
public class MapperHandler {

    private static final String MAPPER_INTERFACE_NAMES = "MybatisMapperInterfaceNames";

    private final ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver();

    /**
     * 处理插件中的Mapper
     *
     * @param pluginInfo    插件信息
     * @param processMapper Mapper的具体处理者
     */
    public void processMapper(PluginInfo pluginInfo,
                              MapperHandler.ProcessMapper processMapper) {
        AnnotationConfigApplicationContext applicationContext = pluginInfo.getPluginApplicationContext();
        // TODO 这里可以把类进行分组，就不用每次都扫mapper
        List<Class<?>> mapperClassList = new ArrayList<>();
        for (Class<?> aClass : pluginInfo.getClassList()) {
            Mapper annotation = aClass.getAnnotation(Mapper.class);
            if (annotation != null) {
                mapperClassList.add(aClass);
            }
        }

        String pluginId = pluginInfo.getPluginId();
        for (Class<?> mapperClass : mapperClassList) {
            if (mapperClass == null) {
                continue;
            }
//            BeanNameGenerator beanNameGenerator = new PluginAnnotationBeanNameGenerator(pluginId);
            AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(mapperClass);
            ScopeMetadata scopeMetadata = scopeMetadataResolver.resolveScopeMetadata(abd);
            abd.setScope(scopeMetadata.getScopeName());
//            String beanName = beanNameGenerator.generateBeanName(abd, applicationContext);
            String beanName = abd.getBeanClassName();
            BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
            AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
            BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, applicationContext);
            try {
                processMapper.process(definitionHolder, mapperClass);
            } catch (Exception e) {
                log.error("process mapper '{}' error. {}", mapperClass.getName(), e.getMessage(), e);
            }
        }
    }


    /**
     * 公共注册生成代理Mapper接口
     *
     * @param holder             ignore
     * @param mapperClass        ignore
     * @param sqlSessionFactory  ignore
     * @param sqlSessionTemplate ignore
     */
    public void commonProcessMapper(BeanDefinitionHolder holder,
                                    Class<?> mapperClass,
                                    SqlSessionFactory sqlSessionFactory,
                                    SqlSessionTemplate sqlSessionTemplate) {
        GenericBeanDefinition definition = (GenericBeanDefinition) holder.getBeanDefinition();
        definition.getConstructorArgumentValues().addGenericArgumentValue(mapperClass);
        definition.setBeanClass(MapperFactoryBean.class);
        definition.getPropertyValues().add("addToConfig", true);
        definition.getPropertyValues().add("sqlSessionFactory", sqlSessionFactory);
        definition.getPropertyValues().add("sqlSessionTemplate", sqlSessionTemplate);
        definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
    }


    @FunctionalInterface
    public interface ProcessMapper {
        void process(BeanDefinitionHolder holder, Class<?> mapperClass) throws Exception;
    }

}
