package com.easyagents.agent.runtime.agentscope;

import com.easyagents.agent.runtime.AgentRuntimeException;
import com.easyagents.agent.runtime.model.AgentGenerationOptions;
import com.easyagents.agent.runtime.model.AgentHttpVersionPolicy;
import com.easyagents.agent.runtime.model.AgentModelFactory;
import com.easyagents.agent.runtime.model.AgentModelProviderType;
import com.easyagents.agent.runtime.model.AgentModelSpec;
import com.easyagents.agent.runtime.model.AgentMessageContentFormat;
import io.agentscope.core.formatter.openai.DeepSeekFormatter;
import io.agentscope.core.formatter.openai.GLMFormatter;
import io.agentscope.core.model.*;
import io.agentscope.core.model.ollama.OllamaOptions;

import java.util.Map;

/**
 * 根据运行时模型声明创建 AgentScope 模型实例。
 */
public class AgentScopeModelFactory implements AgentModelFactory<Model> {

    private static final String DEEPSEEK_BASE_URL = "https://api.deepseek.com";
    private static final String GLM_BASE_URL = "https://open.bigmodel.cn/api/paas/v4";
    private static final String MINIMAX_BASE_URL = "https://api.minimax.io/v1";
    private static final String MOONSHOT_BASE_URL = "https://api.moonshot.cn/v1";
    private static final String ARK_BASE_URL = "https://ark.cn-beijing.volces.com/api/v3";
    private static final String SILICONFLOW_BASE_URL = "https://api.siliconflow.cn/v1";

    private final AgentHttpTransportProvider httpTransportProvider;

    /**
     * 使用进程级共享 Transport 提供器创建模型工厂。
     */
    public AgentScopeModelFactory() {
        this(AgentHttpTransportProvider.shared());
    }

    /**
     * 使用指定 Transport 提供器创建模型工厂。
     *
     * @param httpTransportProvider Transport 提供器
     */
    AgentScopeModelFactory(AgentHttpTransportProvider httpTransportProvider) {
        this.httpTransportProvider = httpTransportProvider;
    }

    @Override
    public Model create(AgentModelSpec modelSpec, AgentGenerationOptions generationOptions) {
        if (modelSpec == null) {
            throw new AgentRuntimeException("Agent model spec is required.");
        }
        GenerateOptions options = toGenerateOptions(modelSpec, generationOptions);
        AgentModelProviderType providerType = modelSpec.getProviderType();
        validateHttpTransportSupport(providerType, modelSpec.getHttpVersionPolicy());
        if (providerType == AgentModelProviderType.OLLAMA) {
            return buildOllama(modelSpec, options);
        }
        if (providerType == AgentModelProviderType.OPENAI) {
            return buildOpenAi(modelSpec, options);
        }
        if (providerType == AgentModelProviderType.ANTHROPIC) {
            return buildAnthropic(modelSpec, options);
        }
        if (providerType == AgentModelProviderType.GEMINI) {
            return buildGemini(modelSpec, options);
        }
        if (providerType == AgentModelProviderType.DEEPSEEK) {
            return buildDeepSeek(modelSpec, options);
        }
        if (providerType == AgentModelProviderType.GLM) {
            return buildGlm(modelSpec, options);
        }
        if (providerType == AgentModelProviderType.MINIMAX) {
            return buildOpenAiCompatible(modelSpec, options, MINIMAX_BASE_URL);
        }
        if (providerType == AgentModelProviderType.MOONSHOT) {
            return buildOpenAiCompatible(modelSpec, options, MOONSHOT_BASE_URL);
        }
        if (providerType == AgentModelProviderType.ARK) {
            return buildOpenAiCompatible(modelSpec, options, ARK_BASE_URL);
        }
        if (providerType == AgentModelProviderType.SILICONFLOW) {
            return buildOpenAiCompatible(modelSpec, options, SILICONFLOW_BASE_URL);
        }
        if (providerType == AgentModelProviderType.DASHSCOPE) {
            return buildDashScope(modelSpec, generationOptions, options);
        }
        if (providerType == AgentModelProviderType.OPENAI_COMPATIBLE || providerType == AgentModelProviderType.CUSTOM) {
            return buildOpenAiCompatible(modelSpec, options, null);
        }
        throw new AgentRuntimeException("Unsupported agent model provider: " + providerType);
    }

    /**
     * 将中立参数转换为 AgentScope 参数。
     *
     * @param modelSpec 模型声明
     * @param options 中立参数
     * @return AgentScope 参数
     */
    public GenerateOptions toGenerateOptions(AgentModelSpec modelSpec, AgentGenerationOptions options) {
        AgentGenerationOptions safeOptions = options == null ? new AgentGenerationOptions() : options;
        GenerateOptions.Builder builder = GenerateOptions.builder()
                .apiKey(modelSpec.getApiKey())
                .baseUrl(modelSpec.getBaseUrl())
                .endpointPath(modelSpec.getEndpointPath())
                .modelName(modelSpec.getModelName())
                .stream(safeOptions.getStream())
                .temperature(safeOptions.getTemperature())
                .topP(safeOptions.getTopP())
                .topK(safeOptions.getTopK())
                .maxTokens(safeOptions.getMaxTokens())
                .maxCompletionTokens(safeOptions.getMaxCompletionTokens())
                .thinkingBudget(safeOptions.getThinkingBudget())
                .reasoningEffort(safeOptions.getReasoningEffort());
        for (Map.Entry<String, Object> entry : safeOptions.getAdditionalBodyParams().entrySet()) {
            builder.additionalBodyParam(entry.getKey(), entry.getValue());
        }
        for (Map.Entry<String, String> entry : safeOptions.getAdditionalHeaders().entrySet()) {
            builder.additionalHeader(entry.getKey(), entry.getValue());
        }
        for (Map.Entry<String, String> entry : safeOptions.getAdditionalQueryParams().entrySet()) {
            builder.additionalQueryParam(entry.getKey(), entry.getValue());
        }
        return builder.build();
    }

    /**
     * 构建 OpenAI 原生模型。
     *
     * @param modelSpec 模型声明
     * @param options 生成参数
     * @return 模型
     */
    private Model buildOpenAi(AgentModelSpec modelSpec, GenerateOptions options) {
        return buildOpenAiCompatible(modelSpec, options, null);
    }

    /**
     * 通过 OpenAI-compatible 协议构建模型。
     *
     * @param modelSpec 模型声明
     * @param options 生成参数
     * @param defaultBaseUrl 默认基础 URL
     * @return 模型
     */
    private Model buildOpenAiCompatible(AgentModelSpec modelSpec, GenerateOptions options, String defaultBaseUrl) {
        String baseUrl = resolveBaseUrl(modelSpec, defaultBaseUrl);
        OpenAIChatModel.Builder builder = OpenAIChatModel.builder()
                .apiKey(modelSpec.getApiKey())
                .modelName(modelSpec.getModelName())
                .baseUrl(baseUrl)
                .endpointPath(modelSpec.getEndpointPath())
                .stream(Boolean.TRUE.equals(options.getStream()))
                .httpTransport(httpTransportProvider.getTransport(modelSpec.getHttpVersionPolicy(), baseUrl))
                .generateOptions(options);
        if (modelSpec.getMessageContentFormat() == AgentMessageContentFormat.TEXT_PARTS) {
            builder.formatter(new AgentOpenAIChatFormatter());
        }
        return builder.build();
    }

    /**
     * 构建 Anthropic 模型。
     *
     * @param modelSpec 模型声明
     * @param options 生成参数
     * @return 模型
     */
    private Model buildAnthropic(AgentModelSpec modelSpec, GenerateOptions options) {
        return AnthropicChatModel.builder()
                .apiKey(modelSpec.getApiKey())
                .modelName(modelSpec.getModelName())
                .baseUrl(modelSpec.getBaseUrl())
                .stream(Boolean.TRUE.equals(options.getStream()))
                .defaultOptions(options)
                .build();
    }

    /**
     * 构建 Gemini 模型。
     *
     * @param modelSpec 模型声明
     * @param options 生成参数
     * @return 模型
     */
    private Model buildGemini(AgentModelSpec modelSpec, GenerateOptions options) {
        return GeminiChatModel.builder()
                .apiKey(modelSpec.getApiKey())
                .modelName(modelSpec.getModelName())
                .baseUrl(modelSpec.getBaseUrl())
                .streamEnabled(Boolean.TRUE.equals(options.getStream()))
                .defaultOptions(options)
                .build();
    }

    /**
     * 通过 OpenAI-compatible 协议构建 DeepSeek 模型。
     *
     * @param modelSpec 模型声明
     * @param options 生成参数
     * @return 模型
     */
    private Model buildDeepSeek(AgentModelSpec modelSpec, GenerateOptions options) {
        String baseUrl = resolveBaseUrl(modelSpec, DEEPSEEK_BASE_URL);
        OpenAIChatModel.Builder builder = OpenAIChatModel.builder()
                .apiKey(modelSpec.getApiKey())
                .modelName(modelSpec.getModelName())
                .baseUrl(baseUrl)
                .endpointPath(modelSpec.getEndpointPath())
                .stream(Boolean.TRUE.equals(options.getStream()))
                .httpTransport(httpTransportProvider.getTransport(modelSpec.getHttpVersionPolicy(), baseUrl))
                .formatter(modelSpec.getMessageContentFormat() == AgentMessageContentFormat.TEXT_PARTS
                        ? new AgentDeepSeekChatFormatter()
                        : new DeepSeekFormatter())
                .generateOptions(options);
        return builder.build();
    }

    /**
     * 通过 OpenAI-compatible 协议构建智谱 GLM 模型。
     *
     * @param modelSpec 模型声明
     * @param options 生成参数
     * @return 模型
     */
    private Model buildGlm(AgentModelSpec modelSpec, GenerateOptions options) {
        String baseUrl = resolveBaseUrl(modelSpec, GLM_BASE_URL);
        OpenAIChatModel.Builder builder = OpenAIChatModel.builder()
                .apiKey(modelSpec.getApiKey())
                .modelName(modelSpec.getModelName())
                .baseUrl(baseUrl)
                .endpointPath(modelSpec.getEndpointPath())
                .stream(Boolean.TRUE.equals(options.getStream()))
                .httpTransport(httpTransportProvider.getTransport(modelSpec.getHttpVersionPolicy(), baseUrl))
                .formatter(modelSpec.getMessageContentFormat() == AgentMessageContentFormat.TEXT_PARTS
                        ? new AgentGLMChatFormatter()
                        : new GLMFormatter())
                .generateOptions(options);
        return builder.build();
    }

    /**
     * 构建 Ollama 模型。
     *
     * @param modelSpec 模型声明
     * @param options 生成参数
     * @return 模型
     */
    private Model buildOllama(AgentModelSpec modelSpec, GenerateOptions options) {
        return OllamaChatModel.builder()
                .modelName(modelSpec.getModelName())
                .baseUrl(modelSpec.getBaseUrl())
                .defaultOptions(OllamaOptions.fromGenerateOptions(options))
                .build();
    }

    /**
     * 构建 DashScope 模型。
     *
     * @param modelSpec 模型声明
     * @param generationOptions 中立生成参数
     * @param options AgentScope 生成参数
     * @return 模型
     */
    private Model buildDashScope(AgentModelSpec modelSpec, AgentGenerationOptions generationOptions, GenerateOptions options) {
        Boolean thinkingEnabled = generationOptions == null ? null : generationOptions.getThinkingEnabled();
        String baseUrl = modelSpec.getBaseUrl();
        return DashScopeChatModel.builder()
                .apiKey(modelSpec.getApiKey())
                .modelName(modelSpec.getModelName())
                .baseUrl(baseUrl)
                .stream(Boolean.TRUE.equals(options.getStream()))
                .enableThinking(thinkingEnabled)
                .httpTransport(httpTransportProvider.getTransport(modelSpec.getHttpVersionPolicy(), baseUrl))
                .defaultOptions(options)
                .build();
    }

    /**
     * 校验当前 Provider 是否支持显式 Agent HTTP Transport。
     *
     * @param providerType 模型供应商类型
     * @param policy HTTP 版本策略
     */
    private void validateHttpTransportSupport(AgentModelProviderType providerType,
                                              AgentHttpVersionPolicy policy) {
        if (policy == null || policy == AgentHttpVersionPolicy.AUTO) {
            return;
        }
        if (providerType == AgentModelProviderType.ANTHROPIC
                || providerType == AgentModelProviderType.GEMINI
                || providerType == AgentModelProviderType.OLLAMA) {
            throw new AgentRuntimeException(
                    "Agent HTTP transport policy " + policy
                            + " is not supported by provider " + providerType
                            + "; use AUTO for this provider.");
        }
    }

    /**
     * 优先使用调用方传入的基础 URL，未传入时使用供应商默认地址。
     *
     * @param modelSpec 模型声明
     * @param defaultBaseUrl 默认基础 URL
     * @return 最终基础 URL
     */
    private String resolveBaseUrl(AgentModelSpec modelSpec, String defaultBaseUrl) {
        if (modelSpec.getBaseUrl() == null || modelSpec.getBaseUrl().isBlank()) {
            return defaultBaseUrl;
        }
        return modelSpec.getBaseUrl();
    }
}
