package com.huangzj.base.cmd;

import com.google.protobuf.Message;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import org.springframework.util.ClassUtils;

/**
 * 从继承 {@link AbstractTypedPbCommand} 的具体命令类上解析 CTS / STC 消息类型（第二泛参为 {@code Xxx.Builder} 时，STC 取 {@code Xxx}）。
 */
final class TypedPbCommandReflect {

    private TypedPbCommandReflect() {}

    record CtsStc(Class<? extends Message> cts, Class<? extends Message> stc) {}

    static java.util.Optional<CtsStc> resolveCtsStc(Class<?> commandClass) {
        Class<?> user = ClassUtils.getUserClass(commandClass);
        ParameterizedType pt = findAbstractTypedSuper(user);
        if (pt == null) {
            // 非 AbstractTypedPbCommand 子类，或泛型在运行期被擦除到无法解析
            return java.util.Optional.empty();
        }
        Type[] args = pt.getActualTypeArguments();
        if (args.length < 2) {
            return java.util.Optional.empty();
        }
        Class<?> ctsClass = rawClass(args[0]);
        Class<?> builderOrSecond = rawClass(args[1]);
        if (ctsClass == null
                || builderOrSecond == null
                || !Message.class.isAssignableFrom(ctsClass)) {
            return java.util.Optional.empty();
        }
        // Java PB 惯例：Message.Builder 为 Message 的静态内部类，外层即 STC 类型
        Class<?> stcClass = builderOrSecond.getDeclaringClass();
        if (stcClass == null || !Message.class.isAssignableFrom(stcClass)) {
            return java.util.Optional.empty();
        }
        return java.util.Optional.of(
                new CtsStc(ctsClass.asSubclass(Message.class), stcClass.asSubclass(Message.class)));
    }

    private static ParameterizedType findAbstractTypedSuper(Class<?> c) {
        while (c != null && c != Object.class) {
            Type t = c.getGenericSuperclass();
            if (t instanceof ParameterizedType p && p.getRawType() == AbstractTypedPbCommand.class) {
                return p;
            }
            c = c.getSuperclass();
        }
        return null;
    }

    private static Class<?> rawClass(Type t) {
        if (t instanceof Class<?> cl) {
            return cl;
        }
        if (t instanceof ParameterizedType p && p.getRawType() instanceof Class<?> cl) {
            return cl;
        }
        return null;
    }
}
