package com.easyagents.agent.runtime.agentscope;

import com.easyagents.agent.runtime.message.*;
import io.agentscope.core.message.*;

import java.time.Instant;
import java.time.OffsetDateTime;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Base64;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * 运行时消息与 AgentScope 消息的双向适配器。
 */
public class AgentScopeMessageAdapter {

    /** AgentScope URLSource 中用于持久化业务媒体引用的私有协议。 */
    public static final String MEDIA_REFERENCE_SCHEME = "easyagents-media://";

    /**
     * 将运行时消息转换为 AgentScope 消息。
     *
     * @param message 运行时消息
     * @return AgentScope 消息
     */
    public Msg toMsg(AgentMessage message) {
        if (message == null) {
            return null;
        }
        return Msg.builder()
                .id(message.getMessageId())
                .name(message.getName())
                .role(toRole(message.getRole()))
                .content(toContentBlocks(message.getContentBlocks()))
                .metadata(copyMap(message.getMetadata()))
                .timestamp(message.getCreatedAt() == null ? null : message.getCreatedAt().toString())
                .build();
    }

    /**
     * 将 AgentScope 消息转换为运行时消息。
     *
     * @param msg AgentScope 消息
     * @return 运行时消息
     */
    public AgentMessage toAgentMessage(Msg msg) {
        if (msg == null) {
            return null;
        }
        AgentMessage message = new AgentMessage();
        message.setMessageId(msg.getId());
        message.setName(msg.getName());
        message.setRole(toRole(msg.getRole()));
        message.setMetadata(msg.getMetadata());
        if (msg.getTimestamp() != null && !msg.getTimestamp().isBlank()) {
            Instant parsed = parseTimestamp(msg.getTimestamp());
            if (parsed != null) {
                message.setCreatedAt(parsed);
            } else {
                message.getMetadata().put("rawTimestamp", msg.getTimestamp());
            }
        }
        message.setContentBlocks(toBlocks(msg.getContent()));
        return message;
    }

    /**
     * 将 AgentScope 块转换为运行时块。
     *
     * @param block AgentScope 块
     * @return 运行时块
     */
    public AgentContentBlock toAgentBlock(ContentBlock block) {
        if (block == null) {
            return null;
        }
        if (block instanceof TextBlock textBlock) {
            return new AgentTextBlock(textBlock.getText());
        }
        if (block instanceof ThinkingBlock thinkingBlock) {
            AgentThinkingBlock converted = new AgentThinkingBlock(thinkingBlock.getThinking());
            converted.getMetadata().putAll(copyMap(thinkingBlock.getMetadata()));
            return converted;
        }
        if (block instanceof ToolUseBlock toolUseBlock) {
            AgentToolUseBlock converted = new AgentToolUseBlock(toolUseBlock.getId(), toolUseBlock.getName(), copyMap(toolUseBlock.getInput()));
            converted.setContent(toolUseBlock.getContent());
            converted.getMetadata().putAll(copyMap(toolUseBlock.getMetadata()));
            return converted;
        }
        if (block instanceof ToolResultBlock toolResultBlock) {
            AgentToolResultBlock converted = new AgentToolResultBlock(toolResultBlock.getId(), toolResultBlock.getName());
            converted.setOutput(toBlocks(toolResultBlock.getOutput()));
            converted.setSuspended(toolResultBlock.isSuspended());
            converted.getMetadata().putAll(copyMap(toolResultBlock.getMetadata()));
            return converted;
        }
        if (block instanceof ImageBlock imageBlock) {
            return toMediaBlock(imageBlock, "image");
        }
        if (block instanceof AudioBlock audioBlock) {
            return toMediaBlock(audioBlock, "audio");
        }
        if (block instanceof VideoBlock videoBlock) {
            return toMediaBlock(videoBlock, "video");
        }
        AgentUnknownBlock converted = new AgentUnknownBlock();
        converted.setSourceClassName(block.getClass().getName());
        converted.setSourceTypeName(resolveTypeName(block));
        converted.setRawText(block.toString());
        converted.getRawMetadata().put("className", block.getClass().getName());
        return converted;
    }

    /**
     * 将运行时块转换为 AgentScope 块。
     *
     * @param block 运行时块
     * @return AgentScope 块
     */
    public ContentBlock toContentBlock(AgentContentBlock block) {
        if (block == null) {
            return null;
        }
        if (block instanceof AgentTextBlock textBlock) {
            return TextBlock.builder().text(textBlock.getText()).build();
        }
        if (block instanceof AgentThinkingBlock thinkingBlock) {
            return ThinkingBlock.builder()
                    .thinking(thinkingBlock.getThinking())
                    .metadata(copyMap(thinkingBlock.getMetadata()))
                    .build();
        }
        if (block instanceof AgentToolUseBlock toolUseBlock) {
            return ToolUseBlock.builder()
                    .id(toolUseBlock.getId())
                    .name(toolUseBlock.getName())
                    .input(copyMap(toolUseBlock.getInput()))
                    .content(toolUseBlock.getContent())
                    .metadata(copyMap(toolUseBlock.getMetadata()))
                    .build();
        }
        if (block instanceof AgentToolResultBlock toolResultBlock) {
            Map<String, Object> metadata = copyMap(toolResultBlock.getMetadata());
            metadata.put("suspended", toolResultBlock.isSuspended());
            return ToolResultBlock.of(
                    toolResultBlock.getId(),
                    toolResultBlock.getName(),
                    toContentBlocks(toolResultBlock.getOutput()),
                    metadata);
        }
        if (block instanceof AgentMediaBlock mediaBlock) {
            return toMediaBlock(mediaBlock);
        }
        if (block instanceof AgentUnknownBlock unknownBlock) {
            return toUnknownContentBlock(unknownBlock);
        }
        return null;
    }

    /**
     * 将 AgentScope 块列表转换为运行时块列表。
     *
     * @param blocks AgentScope 块列表
     * @return 运行时块列表
     */
    public List<AgentContentBlock> toBlocks(List<ContentBlock> blocks) {
        List<AgentContentBlock> converted = new ArrayList<>();
        if (blocks == null) {
            return converted;
        }
        for (ContentBlock block : blocks) {
            AgentContentBlock agentBlock = toAgentBlock(block);
            if (agentBlock != null) {
                converted.add(agentBlock);
            }
        }
        return converted;
    }

    /**
     * 将运行时块列表转换为 AgentScope 块列表。
     *
     * @param blocks 运行时块列表
     * @return AgentScope 块列表
     */
    public List<ContentBlock> toContentBlocks(List<AgentContentBlock> blocks) {
        List<ContentBlock> converted = new ArrayList<>();
        if (blocks == null) {
            return converted;
        }
        for (AgentContentBlock block : blocks) {
            ContentBlock contentBlock = toContentBlock(block);
            if (contentBlock != null) {
                converted.add(contentBlock);
            }
        }
        return converted;
    }

    private MsgRole toRole(AgentMessageRole role) {
        if (role == AgentMessageRole.ASSISTANT) {
            return MsgRole.ASSISTANT;
        }
        if (role == AgentMessageRole.SYSTEM) {
            return MsgRole.SYSTEM;
        }
        if (role == AgentMessageRole.TOOL) {
            return MsgRole.TOOL;
        }
        return MsgRole.USER;
    }

    private AgentMessageRole toRole(MsgRole role) {
        if (role == MsgRole.ASSISTANT) {
            return AgentMessageRole.ASSISTANT;
        }
        if (role == MsgRole.SYSTEM) {
            return AgentMessageRole.SYSTEM;
        }
        if (role == MsgRole.TOOL) {
            return AgentMessageRole.TOOL;
        }
        return AgentMessageRole.USER;
    }

    private Map<String, Object> copyMap(Map<String, Object> metadata) {
        return metadata == null ? new LinkedHashMap<>() : new LinkedHashMap<>(metadata);
    }

    private ContentBlock toMediaBlock(AgentMediaBlock block) {
        if (block == null) {
            return null;
        }
        if ("audio".equalsIgnoreCase(block.getMediaKind())) {
            return AudioBlock.builder().source(mediaSource(block)).build();
        }
        if ("video".equalsIgnoreCase(block.getMediaKind())) {
            return VideoBlock.builder()
                    .source(mediaSource(block))
                    .fps(block.getFps())
                    .maxFrames(block.getMaxFrames())
                    .minPixels(block.getMinPixels())
                    .maxPixels(block.getMaxPixels())
                    .totalPixels(block.getTotalPixels())
                    .build();
        }
        return ImageBlock.builder()
                .source(mediaSource(block))
                .minPixels(block.getMinPixels())
                .maxPixels(block.getMaxPixels())
                .build();
    }

    private AgentContentBlock toMediaBlock(ContentBlock block, String mediaKind) {
        AgentMediaBlock converted = new AgentMediaBlock(mediaKind);
        if (block instanceof ImageBlock imageBlock) {
            readSource(imageBlock.getSource(), converted);
            converted.setMinPixels(imageBlock.getMinPixels());
            converted.setMaxPixels(imageBlock.getMaxPixels());
        } else if (block instanceof AudioBlock audioBlock) {
            readSource(audioBlock.getSource(), converted);
        } else if (block instanceof VideoBlock videoBlock) {
            readSource(videoBlock.getSource(), converted);
            converted.setFps(videoBlock.getFps());
            converted.setMaxFrames(videoBlock.getMaxFrames());
            converted.setMinPixels(videoBlock.getMinPixels());
            converted.setMaxPixels(videoBlock.getMaxPixels());
            converted.setTotalPixels(videoBlock.getTotalPixels());
        }
        return converted;
    }

    private io.agentscope.core.message.Source mediaSource(AgentMediaBlock block) {
        if (block.getData() != null && !block.getData().isBlank()) {
            return Base64Source.builder()
                    .mediaType(block.getMimeType())
                    .data(block.getData())
                    .build();
        }
        if (block.getReference() != null && !block.getReference().isBlank()) {
            String encodedReference = Base64.getUrlEncoder().withoutPadding()
                    .encodeToString(block.getReference().getBytes(StandardCharsets.UTF_8));
            return URLSource.builder().url(MEDIA_REFERENCE_SCHEME + encodedReference).build();
        }
        return URLSource.builder().url(block.getUrl()).build();
    }

    private void readSource(io.agentscope.core.message.Source source, AgentMediaBlock block) {
        if (source instanceof Base64Source base64Source) {
            block.setMimeType(base64Source.getMediaType());
            block.setData(base64Source.getData());
            return;
        }
        if (source instanceof URLSource urlSource) {
            String url = urlSource.getUrl();
            if (url != null && url.startsWith(MEDIA_REFERENCE_SCHEME)) {
                block.setReference(decodeReference(url));
            } else {
                block.setUrl(url);
            }
        }
    }

    /**
     * 从 AgentScope 私有 URLSource 解码业务媒体引用。
     *
     * @param url 私有协议 URL
     * @return 原始业务媒体引用
     */
    public static String decodeReference(String url) {
        if (url == null || !url.startsWith(MEDIA_REFERENCE_SCHEME)) {
            return null;
        }
        String encoded = url.substring(MEDIA_REFERENCE_SCHEME.length());
        try {
            return new String(Base64.getUrlDecoder().decode(encoded), StandardCharsets.UTF_8);
        } catch (IllegalArgumentException error) {
            throw new IllegalArgumentException("Invalid agent media reference.", error);
        }
    }

    private ContentBlock toUnknownContentBlock(AgentUnknownBlock block) {
        String text = block.getRawText();
        if (text == null || text.isBlank()) {
            text = "[unsupported content block: " + block.getSourceTypeName() + "]";
        }
        return TextBlock.builder()
                .text(text)
                .build();
    }

    private Instant parseTimestamp(String timestamp) {
        try {
            return Instant.parse(timestamp);
        } catch (Exception ignored) {
            // 继续尝试其他格式。
        }
        try {
            return OffsetDateTime.parse(timestamp).toInstant();
        } catch (Exception ignored) {
            // 继续尝试其他格式。
        }
        try {
            return Instant.ofEpochMilli(Long.parseLong(timestamp));
        } catch (Exception ignored) {
            return null;
        }
    }

    private String resolveTypeName(ContentBlock block) {
        if (block instanceof TextBlock) {
            return "text";
        }
        if (block instanceof ThinkingBlock) {
            return "thinking";
        }
        if (block instanceof ToolUseBlock) {
            return "tool_use";
        }
        if (block instanceof ToolResultBlock) {
            return "tool_result";
        }
        if (block instanceof ImageBlock) {
            return "image";
        }
        if (block instanceof AudioBlock) {
            return "audio";
        }
        if (block instanceof VideoBlock) {
            return "video";
        }
        return block.getClass().getSimpleName();
    }
}
