package cn.axzo.msg.center.notices.client.config;

import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.InterceptorChain;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSessionFactory;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author yanglin
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class PaginationConfig implements ApplicationListener<ContextRefreshedEvent> {

    private final SqlSessionFactory sessionFactory;
    private final ConfigurableListableBeanFactory beanFactory;

    @Override
    public void onApplicationEvent(@NotNull ContextRefreshedEvent event) {
        try {
            repair();
            analyze();
        } catch (Exception e) {
            log.warn("failed to handle mybatis plugins", e);
        }
    }

    @SuppressWarnings("unchecked")
    private void repair() {
        Configuration configuration = sessionFactory.getConfiguration();
        Field chainField = ReflectionUtils.findField(configuration.getClass(), "interceptorChain");
        if (chainField == null) return;
        chainField.setAccessible(true);
        InterceptorChain chain = (InterceptorChain) ReflectionUtils.getField(chainField, configuration);
        Field interceptorsField = ReflectionUtils.findField(InterceptorChain.class, "interceptors");
        if (interceptorsField == null) return;
        interceptorsField.setAccessible(true);
        List<Interceptor> interceptors = (List<Interceptor>) ReflectionUtils.getField(interceptorsField, chain);
        if (interceptors == null) return;
        for (Interceptor interceptor : new ArrayList<>(interceptors)) {
            if (interceptor.getClass() == MybatisPlusInterceptor.class) {
                log.info("prepare removing MybatisPlusInterceptor");
                boolean removed = interceptors.remove(interceptor);
                log.info("removed MybatisPlusInterceptor={}", removed);
            }
        }
    }

    private void analyze() {
        Map<String, MybatisPlusInterceptor> name2Bean = beanFactory.getBeansOfType(MybatisPlusInterceptor.class);
        for (String name : name2Bean.keySet()) {
            BeanDefinition definition = beanFactory.getBeanDefinition(name);
            log.warn("analyze mybatis interceptor bean resource: {}", definition.getResourceDescription());
        }
    }

}