package com.gzzm.lobster.tool;

import com.gzzm.lobster.common.ToolCategory;
import com.gzzm.lobster.common.ToolExecutionMode;
import com.gzzm.lobster.common.ToolRiskLevel;

import java.util.Collections;
import java.util.Map;

/**
 * BuiltinToolDefinition —— 内置工具定义 / Built-in tool definition.
 *
 * <p>V2 扩展（2026-04）新增字段：
 * <ul>
 *   <li>{@link #defaultTimeoutMs} —— 单次执行上限，0 表示不限；dispatcher 会用 Future.get(timeout) 强制兜底</li>
 *   <li>{@link #sideEffect} —— 副作用等级，决定是否落审计 / 是否走审批</li>
 * </ul>
 *
 * <p>旧 Builder API 完全保留；新字段不填就用合理默认值（timeoutMs=0 / sideEffect=READ）。
 */
public final class BuiltinToolDefinition {

    private final String toolName;
    private final String displayName;
    private final String description;
    private final Map<String, Object> inputSchema;
    private final Map<String, Object> outputSchema;
    private final ToolExecutionMode mode;
    private final ToolCategory category;
    private final ToolRiskLevel riskLevel;
    private final boolean requireConfirm;

    /** V2 新增：单次执行 timeout ms，0 不限。 */
    private final long defaultTimeoutMs;
    /** V2 新增：副作用等级。 */
    private final SideEffectLevel sideEffect;
    /** 工具级速率限制（次/分钟）/ Per-tool rate override. null 表示走 risk 默认。 */
    private final Integer rateLimitPerMinute;

    private BuiltinToolDefinition(Builder b) {
        this.toolName = b.toolName;
        this.displayName = b.displayName;
        this.description = b.description;
        this.inputSchema = b.inputSchema == null ? Collections.<String, Object>emptyMap() : b.inputSchema;
        this.outputSchema = b.outputSchema == null ? Collections.<String, Object>emptyMap() : b.outputSchema;
        this.mode = b.mode == null ? ToolExecutionMode.SYNC : b.mode;
        this.category = b.category;
        this.riskLevel = b.riskLevel == null ? ToolRiskLevel.READ_ONLY : b.riskLevel;
        this.requireConfirm = b.requireConfirm;
        this.defaultTimeoutMs = b.defaultTimeoutMs;
        // sideEffect 默认按 riskLevel 推断，避免全量 builder 改动
        if (b.sideEffect != null) {
            this.sideEffect = b.sideEffect;
        } else {
            this.sideEffect = inferSideEffect(this.riskLevel);
        }
        this.rateLimitPerMinute = b.rateLimitPerMinute;
    }

    private static SideEffectLevel inferSideEffect(ToolRiskLevel risk) {
        if (risk == null) return SideEffectLevel.READ;
        switch (risk) {
            case READ_ONLY: return SideEffectLevel.READ;
            case WRITE:     return SideEffectLevel.WRITE_LOCAL;
            case BATCH_WRITE:
            case DESTRUCTIVE:
                return SideEffectLevel.WRITE_EXTERNAL;
            default: return SideEffectLevel.READ;
        }
    }

    public static Builder builder() { return new Builder(); }

    public String getToolName() { return toolName; }
    public String getDisplayName() { return displayName; }
    public String getDescription() { return description; }
    public Map<String, Object> getInputSchema() { return inputSchema; }
    public Map<String, Object> getOutputSchema() { return outputSchema; }
    public ToolExecutionMode getMode() { return mode; }
    public ToolCategory getCategory() { return category; }
    public ToolRiskLevel getRiskLevel() { return riskLevel; }
    public boolean isRequireConfirm() { return requireConfirm; }
    public long getDefaultTimeoutMs() { return defaultTimeoutMs; }
    public SideEffectLevel getSideEffect() { return sideEffect; }
    public Integer getRateLimitPerMinute() { return rateLimitPerMinute; }

    public static class Builder {
        private String toolName;
        private String displayName;
        private String description;
        private Map<String, Object> inputSchema;
        private Map<String, Object> outputSchema;
        private ToolExecutionMode mode;
        private ToolCategory category;
        private ToolRiskLevel riskLevel;
        private boolean requireConfirm;
        private long defaultTimeoutMs = 0;
        private SideEffectLevel sideEffect;
        private Integer rateLimitPerMinute;

        public Builder name(String n) { this.toolName = n; return this; }
        public Builder displayName(String n) { this.displayName = n; return this; }
        public Builder description(String d) { this.description = d; return this; }
        public Builder inputSchema(Map<String, Object> s) { this.inputSchema = s; return this; }
        public Builder outputSchema(Map<String, Object> s) { this.outputSchema = s; return this; }
        public Builder mode(ToolExecutionMode m) { this.mode = m; return this; }
        public Builder category(ToolCategory c) { this.category = c; return this; }
        public Builder risk(ToolRiskLevel r) { this.riskLevel = r; return this; }
        public Builder requireConfirm(boolean v) { this.requireConfirm = v; return this; }
        /** V2 新增：单次执行超时（ms），0 或负值表示不限。 */
        public Builder timeoutMs(long v) { this.defaultTimeoutMs = Math.max(0, v); return this; }
        /** V2 新增：显式设置副作用等级。不调用则按 riskLevel 推断。 */
        public Builder sideEffect(SideEffectLevel s) { this.sideEffect = s; return this; }
        /** 工具级 per-minute 覆盖；null/&lt;=0 走 risk 默认。 */
        public Builder rateLimitPerMinute(Integer v) {
            this.rateLimitPerMinute = (v == null || v <= 0) ? null : v;
            return this;
        }

        public BuiltinToolDefinition build() {
            if (toolName == null || toolName.isEmpty())
                throw new IllegalStateException("tool name required");
            if (category == null)
                throw new IllegalStateException("tool category required");
            return new BuiltinToolDefinition(this);
        }
    }
}
