package xtools.boot.core.utils;

import lombok.Getter;
import org.jspecify.annotations.NonNull;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.DefaultSingletonBeanRegistry;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import xtools.base.exception.CommonException;
import xtools.boot.api.enums.BootError;

import java.util.Collection;
import java.util.LinkedList;

/**
 * <p>Title : SpringContextUtils</p>
 * <p>Description : SpringContextUtils</p>
 * <p>DevelopTools : Idea_x64_v2026.1</p>
 * <p>DevelopSystem : macOS Sequoia 15.7.5</p>
 * <p>Company : org.xujun</p>
 *
 * @author : XuJun
 * @version : 5.0.0
 * @date : 2026/01/01 09:30
 */
@Order(-1)
@Component
public class SpringContextUtils implements BeanFactoryPostProcessor, ApplicationContextAware {

    /**
     * "@PostConstruct"注解标记的类中,由于ApplicationContext还未加载,导致空指针
     * 因此实现BeanFactoryPostProcessor注入ConfigurableListableBeanFactory实现bean的操作
     */
    private static ConfigurableListableBeanFactory beanFactory;

    /**
     * Spring 应用上下文环境
     */
    @Getter
    private static ApplicationContext applicationContext;

    /**
     * 获取 ListableBeanFactory
     *
     * @return ListableBeanFactory
     */
    public static ListableBeanFactory getBeanFactory() {
        return null == beanFactory ? applicationContext : beanFactory;
    }

    /**
     * 获取 ConfigurableListableBeanFactory
     *
     * @return ConfigurableListableBeanFactory
     */
    public static ConfigurableListableBeanFactory getConfigurableBeanFactory() {
        ConfigurableListableBeanFactory factory = null;
        if (null != beanFactory) {
            factory = beanFactory;
        } else if (applicationContext instanceof ConfigurableApplicationContext) {
            factory = ((ConfigurableApplicationContext) applicationContext).getBeanFactory();
        }
        return factory;
    }

    /**
     * 根据类的类型获取对应的 Bean
     *
     * @param <T>          类的类型
     * @param requiredType 类型
     * @return Bean
     */
    public static <T> T getBean(Class<T> requiredType) {
        try {
            return getBeanFactory().getBean(requiredType);
        } catch (Exception e) {
            throw CommonException.create(BootError.SPRING_BASE, e, "根据类的类型获取对应的 Bean");
        }
    }

    /**
     * 根据类的类型获取对应的 Bean
     *
     * @param <T>          类的类型
     * @param requiredType 类型
     * @return Bean
     */
    public static <T> T getBeanDefNull(Class<T> requiredType) {
        try {
            return getBeanFactory().getBean(requiredType);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 根据类的类型获取对应的 Bean 列表
     *
     * @param <T>          类的类型
     * @param requiredType 类型
     * @return Bean 列表
     */
    public static <T> Collection<T> getBeanList(Class<T> requiredType) {
        try {
            return new LinkedList<>(getBeanFactory().getBeansOfType(requiredType).values());
        } catch (Exception e) {
            throw CommonException.create(BootError.SPRING_BASE, e, "根据类的类型获取对应的 Bean 列表");
        }
    }

    /**
     * 根据 Bean 名称获取对象
     *
     * @param name Bean 名称
     * @return Bean
     */
    public static Object getBean(String name) {
        try {
            return getBeanFactory().getBean(name);
        } catch (Exception e) {
            throw CommonException.create(BootError.SPRING_BASE, e, "根据 Bean 名称获取对象");
        }
    }

    /**
     * 根据 Bean 名称获取对象
     *
     * @param name Bean 名称
     * @return Bean
     */
    public static Object getBeanDefNull(String name) {
        try {
            return getBeanFactory().getBean(name);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 动态向 Spring 注册 Bean
     *
     * @param <T>      Bean 类型
     * @param beanName 名称
     * @param bean     Bean
     */
    public static <T> void registerBean(String beanName, T bean) {
        final ConfigurableListableBeanFactory factory = getConfigurableBeanFactory();
        factory.autowireBean(bean);
        factory.registerSingleton(beanName, bean);
    }

    /**
     * 注销bean(将Spring中的bean注销，请谨慎使用)
     *
     * @param beanName bean 名称
     */
    public static void unregisterBean(String beanName) {
        final ConfigurableListableBeanFactory factory = getConfigurableBeanFactory();
        if (factory instanceof DefaultSingletonBeanRegistry registry) {
            registry.destroySingleton(beanName);
        }
    }

    /**
     * 发布事件
     *
     * @param event 待发布的事件
     */
    public static void publishAppEvent(ApplicationEvent event) {
        publishEvent(event);
    }

    /**
     * 发布事件
     *
     * @param event 待发布的事件
     */
    public static void publishEvent(Object event) {
        if (null != applicationContext) {
            applicationContext.publishEvent(event);
        }
    }

    /**
     * 设置 Spring 应用上下文环境
     *
     * @param applicationContext ApplicationContext
     */
    @Override
    public void setApplicationContext(@NonNull ApplicationContext applicationContext) throws BeansException {
        SpringContextUtils.applicationContext = applicationContext;
    }

    /**
     * 设置 beanFactory
     *
     * @param beanFactory ConfigurableListableBeanFactory
     */
    @Override
    public void postProcessBeanFactory(@NonNull ConfigurableListableBeanFactory beanFactory) throws BeansException {
        SpringContextUtils.beanFactory = beanFactory;
    }

}
