package com.gzzm.lobster.llm.stream;

/**
 * LlmStreamEvent —— 统一的 LLM 流式事件 / Uniform streaming event from any adapter.
 *
 * <p>所有 adapter（OpenAI / Ollama / MCP / …）向上只产出 {@code LlmStreamEvent}，
 * 文本拼接、tool args delta 合并、usage 累加统一由 {@link LlmStreamAggregator} 处理。
 *
 * <p>Java 8 没有 sealed interface / record，这里用 abstract base + static nested 子类实现。
 * 所有子类都是不可变值对象，只做数据承载。
 *
 * <p>消费端按 {@code instanceof} 判别分支 —— 枚举 {@link Kind} 仅用于审计/调试。
 *
 * @see LlmStreamAggregator
 */
public abstract class LlmStreamEvent {

    public enum Kind {
        TEXT_DELTA, TOOL_CALL_DELTA, TOOL_CALL_COMPLETED, USAGE, FINISH, ERROR
    }

    private final Kind kind;

    protected LlmStreamEvent(Kind kind) {
        this.kind = kind;
    }

    public final Kind getKind() {
        return kind;
    }

    // ---- 子类 ----

    /** 增量文本片段 / Incremental text chunk from model. */
    public static final class TextDelta extends LlmStreamEvent {
        public final String delta;
        public TextDelta(String delta) {
            super(Kind.TEXT_DELTA);
            this.delta = delta == null ? "" : delta;
        }
    }

    /**
     * 工具调用的增量 / Partial tool-call frame (OpenAI 的 delta 合并语义).
     *
     * <p>OpenAI / DeepSeek 流式工具调用会按 index 分多帧到达，
     * 同一 toolCallId 的后续帧累加 {@code argsDelta}。name 只在首帧出现。
     */
    public static final class ToolCallDelta extends LlmStreamEvent {
        public final String toolCallId;
        public final String nameDelta;    // 可为空
        public final String argsDelta;    // 可为空
        public final int    index;        // OpenAI 的 tool_calls[i].index
        public ToolCallDelta(String toolCallId, String nameDelta, String argsDelta, int index) {
            super(Kind.TOOL_CALL_DELTA);
            this.toolCallId = toolCallId;
            this.nameDelta = nameDelta;
            this.argsDelta = argsDelta;
            this.index = index;
        }
    }

    /**
     * 工具调用聚合完成 / Tool call fully assembled.
     *
     * <p>对 Ollama / 非流式工具调用 adapter，可一次性产出该事件；
     * 对流式 adapter，由 {@link LlmStreamAggregator} 在收尾时产出。
     */
    public static final class ToolCallCompleted extends LlmStreamEvent {
        public final String toolCallId;
        public final String name;
        public final String argsJson;
        public ToolCallCompleted(String toolCallId, String name, String argsJson) {
            super(Kind.TOOL_CALL_COMPLETED);
            this.toolCallId = toolCallId;
            this.name = name;
            this.argsJson = argsJson == null ? "{}" : argsJson;
        }
    }

    /** token 用量 / Usage metrics (可能来自 stream 最末帧或单独一帧). */
    public static final class Usage extends LlmStreamEvent {
        public final int promptTokens;
        public final int completionTokens;
        public Usage(int promptTokens, int completionTokens) {
            super(Kind.USAGE);
            this.promptTokens = promptTokens;
            this.completionTokens = completionTokens;
        }
    }

    /** 结束帧 / Finish reason (stop / length / tool_calls / ...). */
    public static final class Finish extends LlmStreamEvent {
        public final String finishReason;
        public Finish(String finishReason) {
            super(Kind.FINISH);
            this.finishReason = finishReason;
        }
    }

    /** 错误帧 / Error frame. retryable=true 时 LlmRuntime 才考虑 fallback. */
    public static final class Error extends LlmStreamEvent {
        public final Throwable cause;
        public final boolean   retryable;
        public Error(Throwable cause, boolean retryable) {
            super(Kind.ERROR);
            this.cause = cause;
            this.retryable = retryable;
        }
    }
}
