package com.huangzj.base.cmd;

import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.util.ClassUtils;

/**
 * 启动时扫描所有 {@link GameCommand} Bean：带 {@link Cmd} 且继承 {@link AbstractTypedPbCommand} 的，
 * 根据注解中的 source/service/method 与泛型上的 CTS/STC 自动 {@link ProtoRegistry#register}。
 * 未继承强类型基类（如纯透传）的命令不注册，由网络层按无 {@link ProtoInfo} 处理。
 */
@Slf4j
@Component
public class ProtoRegistryAutoConfigurer implements SmartInitializingSingleton {

    private final ApplicationContext applicationContext;
    private final ProtoRegistry protoRegistry;

    public ProtoRegistryAutoConfigurer(ApplicationContext applicationContext, ProtoRegistry protoRegistry) {
        this.applicationContext = applicationContext;
        this.protoRegistry = protoRegistry;
    }

    @Override
    public void afterSingletonsInstantiated() {
        Map<String, GameCommand> beans = applicationContext.getBeansOfType(GameCommand.class);
        AtomicInteger n = new AtomicInteger();
        for (GameCommand bean : beans.values()) {
            Class<?> userClass = ClassUtils.getUserClass(bean.getClass());
            Cmd cmd = userClass.getAnnotation(Cmd.class);
            if (cmd == null) {
                continue;
            }
            // 仅 AbstractTypedPbCommand 子类可解析泛型；GameCommand 裸实现（如路径3中继）不注册 ProtoInfo
            TypedPbCommandReflect.resolveCtsStc(userClass)
                    .ifPresent(pair -> {
                        ProtoInfo info =
                                new ProtoInfo(cmd.source(), cmd.serviceId(), cmd.methodId(), pair.cts(), pair.stc());
                        protoRegistry.register(info);
                        n.incrementAndGet();
                        log.info(
                                "ProtoInfo registered: source={} service={} method={} cts={} stc={}",
                                cmd.source(),
                                cmd.serviceId(),
                                cmd.methodId(),
                                pair.cts().getSimpleName(),
                                pair.stc().getSimpleName());
                    });
        }
        log.info("ProtoRegistry auto-registration done, {} ProtoInfo bean(s)", n.get());
    }
}
