package tech.easyflow.ai.service.discovery;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import tech.easyflow.ai.entity.Model;
import tech.easyflow.ai.entity.ModelProvider;
import tech.easyflow.ai.mapper.ModelMapper;
import tech.easyflow.ai.mapper.ModelProviderMapper;
import tech.easyflow.ai.service.ModelProviderService;
import tech.easyflow.ai.service.ModelService;
import tech.easyflow.ai.service.capability.ModelCapabilityCatalog;
import tech.easyflow.ai.service.capability.ModelCapabilityResolver;

import com.fasterxml.jackson.databind.ObjectMapper;

import java.lang.reflect.Proxy;
import java.math.BigInteger;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 远端模型幂等导入服务测试。
 */
public class RemoteModelImportServiceTest {

    /** 测试服务商 ID。 */
    private static final BigInteger PROVIDER_ID = BigInteger.valueOf(100);

    /** 测试服务商。 */
    private ModelProvider provider;
    /** 预置的已存在模型。 */
    private Model existingModel;
    /** 保存调用次数。 */
    private final AtomicInteger saveCount = new AtomicInteger();
    /** 待测试服务。 */
    private RemoteModelImportService importService;

    /**
     * 初始化测试夹具。
     */
    @Before
    public void setUp() {
        provider = new ModelProvider();
        provider.setId(PROVIDER_ID);
        provider.setProviderType("openai");
        existingModel = null;
        saveCount.set(0);

        ModelProviderService providerService = proxy(ModelProviderService.class,
                (method, arguments) -> "getById".equals(method) ? provider : defaultValue(method));
        ModelProviderMapper providerMapper = proxy(ModelProviderMapper.class,
                (method, arguments) -> "lockById".equals(method) ? PROVIDER_ID : defaultValue(method));
        ModelMapper modelMapper = proxy(ModelMapper.class,
                (method, arguments) -> "selectOneByQuery".equals(method)
                        ? existingModel : defaultValue(method));
        ModelService modelService = proxy(ModelService.class, (method, arguments) -> {
            if ("save".equals(method)) {
                Model target = (Model) arguments[0];
                target.setId(BigInteger.valueOf(201));
                saveCount.incrementAndGet();
                return true;
            }
            return defaultValue(method);
        });
        ModelCapabilityCatalog catalog = new ModelCapabilityCatalog(new ObjectMapper());
        RemoteModelMetadataResolver metadataResolver = new RemoteModelMetadataResolver(
                catalog, new ModelCapabilityResolver(catalog));
        importService = new RemoteModelImportService(
                providerService, providerMapper, modelService, modelMapper, metadataResolver);
    }

    /**
     * 验证命中已有模型时返回幂等结果且不重复保存。
     */
    @Test
    public void shouldReturnAlreadyExistsWithoutSaving() {
        Model existing = new Model();
        existing.setId(BigInteger.valueOf(200));
        existing.setModelName("gpt-5");
        existing.setModelType(Model.MODEL_TYPES[0]);
        existingModel = existing;

        RemoteModelImportResult result = importService.importModel(
                PROVIDER_ID, "gpt-5", new Model());

        Assert.assertEquals(RemoteModelImportStatus.ALREADY_EXISTS, result.getStatus());
        Assert.assertEquals(existing.getId(), result.getLocalModelId());
        Assert.assertEquals(0, saveCount.get());
    }

    /**
     * 验证新模型完成默认值补全和保存。
     */
    @Test
    public void shouldCreateModelWhenNotExists() {
        RemoteModelImportResult result = importService.importModel(
                PROVIDER_ID, " gpt-5 ", new Model());

        Assert.assertEquals(RemoteModelImportStatus.CREATED, result.getStatus());
        Assert.assertEquals(BigInteger.valueOf(201), result.getLocalModelId());
        Assert.assertEquals(1, saveCount.get());
    }

    /**
     * 创建按方法名返回结果的 JDK 动态接口替身。
     *
     * @param type 接口类型
     * @param handler 方法处理器
     * @param <T> 接口类型
     * @return 接口替身
     */
    private <T> T proxy(Class<T> type, TestInvocationHandler handler) {
        Object value = Proxy.newProxyInstance(
                type.getClassLoader(),
                new Class<?>[]{type},
                (proxy, method, arguments) -> handler.invoke(method.getName(), arguments));
        return type.cast(value);
    }

    /**
     * 返回方法返回类型的基础默认值。
     *
     * @param methodName 方法名
     * @return 默认值
     */
    private Object defaultValue(String methodName) {
        if ("count".equals(methodName)) {
            return 0L;
        }
        return null;
    }

    /**
     * 测试接口方法处理器。
     */
    @FunctionalInterface
    private interface TestInvocationHandler {

        /**
         * 处理接口方法调用。
         *
         * @param method 方法名
         * @param arguments 方法参数
         * @return 方法结果
         */
        Object invoke(String method, Object[] arguments);
    }
}
