package com.lingniu.ingest.core.dispatcher;

import com.lingniu.ingest.api.annotation.AsyncBatch;
import com.lingniu.ingest.api.annotation.IdempotentKey;
import com.lingniu.ingest.api.annotation.MessageMapping;
import com.lingniu.ingest.api.annotation.ProtocolHandler;
import com.lingniu.ingest.api.annotation.RateLimited;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.annotation.AnnotatedElementUtils;

import java.lang.reflect.Method;

/**
 * Spring BeanPostProcessor：扫描带 {@link ProtocolHandler} 注解的 Bean，
 * 把每个带 {@link MessageMapping} 的方法注册到 {@link HandlerRegistry}。
 *
 * <p>替代旧代码里遍布的 {@code if (msgId == 0x0100) ... else if (msgId == 0x0102) ...} 风格。
 */
public class AnnotationHandlerBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware {

    private static final Logger log = LoggerFactory.getLogger(AnnotationHandlerBeanPostProcessor.class);

    private HandlerRegistry registry;
    private BeanFactory beanFactory;

    public AnnotationHandlerBeanPostProcessor() {
    }

    public AnnotationHandlerBeanPostProcessor(HandlerRegistry registry) {
        this.registry = registry;
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        Class<?> type = bean.getClass();
        ProtocolHandler classAnno = AnnotatedElementUtils.findMergedAnnotation(type, ProtocolHandler.class);
        if (classAnno == null) return bean;

        for (Method method : type.getMethods()) {
            MessageMapping mapping = AnnotatedElementUtils.findMergedAnnotation(method, MessageMapping.class);
            if (mapping == null) continue;

            Class<?> paramType = method.getParameterCount() > 0 ? method.getParameterTypes()[0] : Object.class;
            int[] commands = mapping.command().length == 0 ? new int[]{0} : mapping.command();
            int[] infoTypes = mapping.infoType().length == 0 ? new int[]{0} : mapping.infoType();

            // 这些注解只声明策略，实际限流、幂等、异步批处理由 Dispatcher/Interceptor 层解释执行。
            RateLimited rl = AnnotatedElementUtils.findMergedAnnotation(method, RateLimited.class);
            IdempotentKey ik = AnnotatedElementUtils.findMergedAnnotation(method, IdempotentKey.class);
            AsyncBatch ab = AnnotatedElementUtils.findMergedAnnotation(method, AsyncBatch.class);

            for (int cmd : commands) {
                for (int info : infoTypes) {
                    HandlerDefinition def = new HandlerDefinition(
                            classAnno.protocol(), cmd, info, mapping.desc(),
                            bean, method, paramType, rl, ik, ab);
                    registry().register(def);
                    log.info("registered handler {} protocol={} command=0x{} info=0x{}",
                            type.getSimpleName() + "#" + method.getName(),
                            classAnno.protocol(), Integer.toHexString(cmd), Integer.toHexString(info));
                }
            }
        }
        return bean;
    }

    private HandlerRegistry registry() {
        if (registry == null) {
            if (beanFactory == null) {
                throw new IllegalStateException("BeanFactory must be set before registering protocol handlers");
            }
            registry = beanFactory.getBean(HandlerRegistry.class);
        }
        return registry;
    }
}
