package jnpf.util.excelv2.util;

import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;

@Component
@Slf4j
public final class SpringBeanUtils implements BeanFactoryPostProcessor {
    /**
     * Spring 应用上下文环境
     */
    private static volatile ConfigurableListableBeanFactory beanFactory;

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        SpringBeanUtils.beanFactory = beanFactory;
        log.info("SpringBeanUtils 初始化完成");
    }

    /**
     * 检查 BeanFactory 是否已初始化
     * @throws IllegalStateException 如果未初始化则抛出异常
     */
    private static void checkInitialized() {
        if (beanFactory == null) {
            throw new IllegalStateException("SpringBeanUtils 尚未初始化，请确保在 Spring 容器启动后再使用");
        }
    }


    @SuppressWarnings("unchecked")
    public static <T> T getBean(String name) throws BeansException {
        checkInitialized();
        try {
            return (T) beanFactory.getBean(name);
        } catch (BeansException e) {
            log.error("获取 Bean 失败，name: {}", name, e);
            throw e;
        }
    }


    public static <T> T getBean(Class<T> clz) throws BeansException {
        checkInitialized();
        try {
            T result = beanFactory.getBean(clz);
            log.debug("成功获取 Bean: {}", clz.getName());
            return result;
        } catch (BeansException e) {
            log.error("获取 Bean 失败，class: {}", clz.getName(), e);
            throw e;
        }
    }

    /**
     * 如果 BeanFactory 包含一个与所给名称匹配的 bean 定义，则返回 true
     *
     * @param name bean 名称
     * @return boolean
     */
    public static boolean containsBean(String name) {
        checkInitialized();
        return beanFactory.containsBean(name);
    }

    /**
     * 判断以给定名字注册的 bean 定义是一个 singleton 还是一个 prototype。如果与给定名字相应的 bean 定义没有被找到，将会抛出一个异常（NoSuchBeanDefinitionException）
     *
     * @param name bean 名称
     * @return boolean true 如果是 singleton，false 如果是 prototype
     * @throws NoSuchBeanDefinitionException 如果找不到对应的 bean 定义
     */
    public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
        checkInitialized();
        return beanFactory.isSingleton(name);
    }

    /**
     * 获取注册对象的类型
     *
     * @param name bean 名称
     * @return Class 注册对象的类型
     * @throws NoSuchBeanDefinitionException 如果找不到对应的 bean 定义
     */
    public static Class<?> getType(String name) throws NoSuchBeanDefinitionException {
        checkInitialized();
        return beanFactory.getType(name);
    }

    /**
     * 如果给定的 bean 名字在 bean 定义中有别名，则返回这些别名
     *
     * @param name bean 名称
     * @return 别名数组
     * @throws NoSuchBeanDefinitionException 如果找不到对应的 bean 定义
     */
    public static String[] getAliases(String name) throws NoSuchBeanDefinitionException {
        checkInitialized();
        return beanFactory.getAliases(name);
    }

    /**
     * 获取 aop 代理对象
     * <p>注意：需要在配置类上添加@EnableAspectJAutoProxy(exposeProxy=true)才能正常使用</p>
     *
     * @param invoker 调用对象
     * @return AOP 代理对象
     * @throws IllegalStateException 如果未暴露代理对象
     */
    @SuppressWarnings("unchecked")
    public static <T> T getAopProxy(T invoker) {
        checkInitialized();
        Object proxy = AopContext.currentProxy();
        if (proxy == null) {
            throw new IllegalStateException("无法获取 AOP 代理，请确保已配置 exposeProxy=true，例如：@EnableAspectJAutoProxy(exposeProxy=true)");
        }
        log.debug("成功获取 AOP 代理对象：{}", invoker.getClass().getName());
        return (T) proxy;
    }
}
