package com.gzzm.lobster.llm;

import com.gzzm.lobster.common.ModelServiceTier;
import net.cyan.thunwind.annotation.ColumnDescription;
import net.cyan.thunwind.annotation.Entity;
import net.cyan.thunwind.annotation.Index;

import java.util.Date;

/**
 * ModelProfile —— 正式模型配置 / Persistent model profile.
 *
 * <p>数据库化是硬原则；本地配置只作为开发态默认值。
 * DB-backed is mandatory; local config is dev-only.
 */
@Entity(table = "AI_MODEL_PROFILE", keys = "modelId")
public class ModelProfile {

    @ColumnDescription(type = "varchar(80)")
    private String modelId;

    @ColumnDescription(type = "varchar(200)")
    private String displayName;

    /** LLM 供应协议族 / provider family, see {@link ModelProvider}. */
    @Index
    private ModelProvider provider;

    /** 调用协议方言 / wire-protocol dialect, see {@link ModelProtocol}. */
    private ModelProtocol protocol;

    @ColumnDescription(type = "varchar(400)", nullable = false)
    private String endpoint;

    @ColumnDescription(type = "varchar(200)")
    private String apiKey;

    @ColumnDescription(type = "number(1)", defaultValue = "1")
    private Boolean nativeToolCalling;

    @ColumnDescription(type = "number(1)", defaultValue = "1")
    private Boolean streaming;

    @ColumnDescription(type = "number(1)", defaultValue = "0")
    private Boolean reasoning;

    /**
     * @deprecated 用 {@link #thinkingMode} 取代。保留供老数据兼容：thinkingMode 为 null 时
     * 看本字段——true → 视作 {@link ModelThinkingMode#on}，false/null → 视作
     * {@link ModelThinkingMode#auto}（不传字段，由 provider 默认决定）。新 profile
     * 应直接配置 thinkingMode，不要再设本字段。
     */
    @Deprecated
    @ColumnDescription(type = "number(1)", defaultValue = "0")
    private Boolean thinkingEnabled;

    /**
     * 思考模式三态 —— 取代二态 thinkingEnabled。
     * <ul>
     *   <li>{@code auto}：adapter 不传 thinking 字段（默认；对 OpenAI / Claude / DeepSeek-V3 等默认不思考的 provider 安全）</li>
     *   <li>{@code on}：显式传 reasoning_effort=high + thinking={type:enabled}</li>
     *   <li>{@code off}：显式传 enable_thinking=false 一组 disable 字段（解决 Qwen3 / DashScope 默认开思考被误伤）</li>
     * </ul>
     */
    private ModelThinkingMode thinkingMode;

    @ColumnDescription(type = "number(1)", defaultValue = "0")
    private Boolean multimodal;

    @ColumnDescription(type = "number(8)")
    private Integer contextWindow;

    @ColumnDescription(type = "number(8)")
    private Integer maxOutputTokens;

    @ColumnDescription(type = "number(8)")
    private Integer firstTokenTimeoutMs;

    @ColumnDescription(type = "number(8)")
    private Integer totalTimeoutMs;

    private ModelServiceTier serviceTier;

    @ColumnDescription(type = "number(1)", defaultValue = "1")
    private Boolean enabled;

    /** 兜底路由优先级：数值越大越优先，同 tier 内按该字段 desc 排序. */
    @ColumnDescription(type = "number(8)", defaultValue = "0")
    private Integer priority;

    @ColumnDescription(type = "varchar(40)")
    private String orgId;

    private Date createTime;
    private Date updateTime;

    public ModelProfile() {}

    public String getModelId() { return modelId; }
    public void setModelId(String modelId) { this.modelId = modelId; }
    public String getDisplayName() { return displayName; }
    public void setDisplayName(String displayName) { this.displayName = displayName; }
    public ModelProvider getProvider() { return provider; }
    public void setProvider(ModelProvider provider) { this.provider = provider; }
    public ModelProtocol getProtocol() { return protocol; }
    public void setProtocol(ModelProtocol protocol) { this.protocol = protocol; }
    public String getEndpoint() { return endpoint; }
    public void setEndpoint(String endpoint) { this.endpoint = endpoint; }
    public String getApiKey() { return apiKey; }
    public void setApiKey(String apiKey) { this.apiKey = apiKey; }
    public Boolean getNativeToolCalling() { return nativeToolCalling; }
    public void setNativeToolCalling(Boolean nativeToolCalling) { this.nativeToolCalling = nativeToolCalling; }
    public Boolean getStreaming() { return streaming; }
    public void setStreaming(Boolean streaming) { this.streaming = streaming; }
    public Boolean getReasoning() { return reasoning; }
    public void setReasoning(Boolean reasoning) { this.reasoning = reasoning; }
    public Boolean getThinkingEnabled() { return thinkingEnabled; }
    public void setThinkingEnabled(Boolean thinkingEnabled) { this.thinkingEnabled = thinkingEnabled; }
    public ModelThinkingMode getThinkingMode() { return thinkingMode; }
    public void setThinkingMode(ModelThinkingMode thinkingMode) { this.thinkingMode = thinkingMode; }

    /**
     * 解析有效的 thinking mode：
     * <ol>
     *   <li>thinkingMode 非 null → 直接用</li>
     *   <li>thinkingMode 为 null + 老 thinkingEnabled=true → 兼容视作 {@link ModelThinkingMode#on}</li>
     *   <li>其它 → {@link ModelThinkingMode#auto}（不传字段）</li>
     * </ol>
     */
    public ModelThinkingMode resolveThinkingMode() {
        if (thinkingMode != null) return thinkingMode;
        if (Boolean.TRUE.equals(thinkingEnabled)) return ModelThinkingMode.on;
        return ModelThinkingMode.auto;
    }

    public Boolean getMultimodal() { return multimodal; }
    public void setMultimodal(Boolean multimodal) { this.multimodal = multimodal; }
    public Integer getContextWindow() { return contextWindow; }
    public void setContextWindow(Integer contextWindow) { this.contextWindow = contextWindow; }
    public Integer getMaxOutputTokens() { return maxOutputTokens; }
    public void setMaxOutputTokens(Integer maxOutputTokens) { this.maxOutputTokens = maxOutputTokens; }
    public Integer getFirstTokenTimeoutMs() { return firstTokenTimeoutMs; }
    public void setFirstTokenTimeoutMs(Integer firstTokenTimeoutMs) { this.firstTokenTimeoutMs = firstTokenTimeoutMs; }
    public Integer getTotalTimeoutMs() { return totalTimeoutMs; }
    public void setTotalTimeoutMs(Integer totalTimeoutMs) { this.totalTimeoutMs = totalTimeoutMs; }
    public ModelServiceTier getServiceTier() { return serviceTier; }
    public void setServiceTier(ModelServiceTier serviceTier) { this.serviceTier = serviceTier; }
    public Boolean getEnabled() { return enabled; }
    public void setEnabled(Boolean enabled) { this.enabled = enabled; }
    public Integer getPriority() { return priority; }
    public void setPriority(Integer priority) { this.priority = priority; }
    public String getOrgId() { return orgId; }
    public void setOrgId(String orgId) { this.orgId = orgId; }
    public Date getCreateTime() { return createTime; }
    public void setCreateTime(Date createTime) { this.createTime = createTime; }
    public Date getUpdateTime() { return updateTime; }
    public void setUpdateTime(Date updateTime) { this.updateTime = updateTime; }
}
