package com.gzzm.lobster.llm;

import com.gzzm.lobster.common.MessageRole;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * LobsterMessage —— 大龙虾内部消息抽象 / Internal message abstraction.
 *
 * <p>协议中立：由 adapter 层翻译到 OpenAI / Ollama / vLLM / Anthropic 各自协议。
 * Protocol-neutral — adapter layer converts to each provider's wire format.
 */
public final class LobsterMessage {

    private final MessageRole role;
    private final String content;
    /** 仅 assistant 消息持有 / Only assistant messages carry tool_calls. */
    private final List<ToolCall> toolCalls;
    /** 仅 tool 消息持有 / Only tool messages carry a tool_call_id. */
    private final String toolCallId;
    private final String toolName;
    /** 多模态附件（图像 URL 列表）/ Multimodal attachments (image URLs). */
    private final List<String> imageUrls;
    /**
     * Assistant 消息的思考内容（thinking-mode 模型专用）. DeepSeek 等要求多轮对话把历史
     * reasoning_content 发回 API. adapter.toOpenAiMessages 会按需序列化该字段.
     */
    private final String reasoningContent;
    /**
     * tool 消息：原始全文外置后的 ContentStore ref（DB 大于 4KB 阈值时由 ThreadService 写入）.
     * 仅用于发送视图层把 ref 嵌入截断标记，让 LLM 通过 read_externalized_content 拉子段；adapter 不序列化它.
     * Tool messages: ContentStore ref of the externalized full content; used solely by the
     * send-view layer to embed a pointer into truncation markers so the model can fetch the
     * full body via read_externalized_content. Adapters do not wire this field.
     */
    private final String fullContentRef;

    private LobsterMessage(MessageRole role, String content, List<ToolCall> toolCalls,
                           String toolCallId, String toolName, List<String> imageUrls,
                           String reasoningContent, String fullContentRef) {
        this.role = role;
        this.content = content;
        this.toolCalls = toolCalls == null ? Collections.<ToolCall>emptyList() : Collections.unmodifiableList(new ArrayList<>(toolCalls));
        this.toolCallId = toolCallId;
        this.toolName = toolName;
        this.imageUrls = imageUrls == null ? Collections.<String>emptyList() : Collections.unmodifiableList(new ArrayList<>(imageUrls));
        this.reasoningContent = reasoningContent;
        this.fullContentRef = fullContentRef;
    }

    public static LobsterMessage system(String content) {
        return new LobsterMessage(MessageRole.system, content, null, null, null, null, null, null);
    }

    public static LobsterMessage user(String content) {
        return new LobsterMessage(MessageRole.user, content, null, null, null, null, null, null);
    }

    public static LobsterMessage userWithImages(String content, List<String> imageUrls) {
        return new LobsterMessage(MessageRole.user, content, null, null, null, imageUrls, null, null);
    }

    public static LobsterMessage assistant(String content) {
        return new LobsterMessage(MessageRole.assistant, content, null, null, null, null, null, null);
    }

    /** thinking-mode assistant 消息（纯文本 + reasoning_content）. */
    public static LobsterMessage assistantWithReasoning(String content, String reasoningContent) {
        return new LobsterMessage(MessageRole.assistant, content, null, null, null, null, reasoningContent, null);
    }

    public static LobsterMessage assistantWithToolCalls(String content, List<ToolCall> toolCalls) {
        return new LobsterMessage(MessageRole.assistant, content, toolCalls, null, null, null, null, null);
    }

    /** thinking-mode assistant 消息带 tool_calls + reasoning_content. */
    public static LobsterMessage assistantWithToolCallsAndReasoning(String content, List<ToolCall> toolCalls,
                                                                    String reasoningContent) {
        return new LobsterMessage(MessageRole.assistant, content, toolCalls, null, null, null, reasoningContent, null);
    }

    public static LobsterMessage tool(String toolCallId, String toolName, String content) {
        return new LobsterMessage(MessageRole.tool, content, null, toolCallId, toolName, null, null, null);
    }

    /** tool 消息携带外置 ref（ContentStore），让发送视图能嵌入 read_externalized_content 提示. */
    public static LobsterMessage toolWithRef(String toolCallId, String toolName, String content,
                                             String fullContentRef) {
        return new LobsterMessage(MessageRole.tool, content, null, toolCallId, toolName, null, null, fullContentRef);
    }

    public MessageRole getRole() { return role; }
    public String getContent() { return content; }
    public List<ToolCall> getToolCalls() { return toolCalls; }
    public String getToolCallId() { return toolCallId; }
    public String getToolName() { return toolName; }
    public List<String> getImageUrls() { return imageUrls; }
    public String getReasoningContent() { return reasoningContent; }
    public String getFullContentRef() { return fullContentRef; }

    public boolean hasToolCalls() { return !toolCalls.isEmpty(); }
    public boolean hasReasoningContent() { return reasoningContent != null && !reasoningContent.isEmpty(); }
    public boolean hasFullContentRef() { return fullContentRef != null && !fullContentRef.isEmpty(); }
}
