package com.gzzm.lobster.llm;

/**
 * ModelCapability —— 模型能力视图 / Projection of a model's streaming / tool-calling capability.
 *
 * <p>绑定到**具体模型**而不是 adapter —— 同一个 {@code OpenAiCompatibleAdapter} 接
 * {@code gpt-4o-mini} 和 {@code deepseek-reasoner} 的能力完全不同；按 adapter 判定会翻车。
 *
 * <p>字段来源于 {@link ModelProfile} 的若干 boolean/int 字段，这里聚合成一个只读视图，
 * 方便 {@link ModelRouter}、{@code LlmStreamAggregator} 一次性读取。
 *
 * <p>Java 8 没有 record，用 public final 字段 + 工厂方法。
 */
public final class ModelCapability {

    /** 是否支持真实流式（SSE / NDJSON）。 */
    public final boolean streaming;

    /** 是否原生支持 tool_calls。false 时需要上层用 prompt 诱导。 */
    public final boolean nativeToolCalling;

    /**
     * 是否支持流式工具调用增量。OpenAI / DeepSeek 通常 true；
     * 早期 Ollama / 部分国产推理框架即使 streaming=true 也可能 false —— 这时
     * 工具调用只能走同步。
     */
    public final boolean toolCallDelta;

    /** 支持多模态输入（图像）。 */
    public final boolean multimodal;

    /** 支持思考/推理模式（o1 / r1 家族）。 */
    public final boolean reasoning;

    /** 上下文窗口（token）。0 表示未知。 */
    public final int contextWindow;

    /** 单次输出上限（token）。0 表示未知。 */
    public final int maxOutputTokens;

    public ModelCapability(boolean streaming, boolean nativeToolCalling, boolean toolCallDelta,
                           boolean multimodal, boolean reasoning,
                           int contextWindow, int maxOutputTokens) {
        this.streaming = streaming;
        this.nativeToolCalling = nativeToolCalling;
        this.toolCallDelta = toolCallDelta;
        this.multimodal = multimodal;
        this.reasoning = reasoning;
        this.contextWindow = contextWindow;
        this.maxOutputTokens = maxOutputTokens;
    }

    /**
     * 从 {@link ModelProfile} 推断能力视图 / Infer capability view from profile.
     *
     * <p>{@code toolCallDelta} 做保守推断：OpenAI / DeepSeek 协议默认支持；
     * Ollama 协议默认 false（见现有 OllamaAdapter 的降级路径）。
     */
    public static ModelCapability from(ModelProfile profile) {
        if (profile == null) {
            return new ModelCapability(false, false, false, false, false, 0, 0);
        }
        boolean streaming = Boolean.TRUE.equals(profile.getStreaming());
        boolean tool = Boolean.TRUE.equals(profile.getNativeToolCalling());
        boolean multi = Boolean.TRUE.equals(profile.getMultimodal());
        boolean reason = Boolean.TRUE.equals(profile.getReasoning());

        // toolCallDelta 按 protocol 保守推断：Ollama 即使开了 tool-calling 也不做流式
        boolean toolCallDelta;
        ModelProtocol proto = profile.getProtocol();
        if (proto == null) {
            toolCallDelta = streaming && tool;
        } else {
            switch (proto) {
                case ollama_chat:
                    toolCallDelta = false;
                    break;
                case chat_completions:
                case messages:
                case vllm_generate:
                default:
                    toolCallDelta = streaming && tool;
            }
        }

        int ctx = profile.getContextWindow() == null ? 0 : profile.getContextWindow();
        int maxOut = profile.getMaxOutputTokens() == null ? 0 : profile.getMaxOutputTokens();
        return new ModelCapability(streaming, tool, toolCallDelta, multi, reason, ctx, maxOut);
    }
}
