package tech.easyflow.ai.invoke.mapper;

import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.springframework.stereotype.Component;
import tech.easyflow.ai.invoke.exception.ModelInvokeException;
import tech.easyflow.ai.invoke.model.UnifiedChatChunk;
import tech.easyflow.ai.invoke.model.UnifiedChatRequest;
import tech.easyflow.ai.invoke.model.UnifiedChatResponse;
import tech.easyflow.ai.invoke.model.UnifiedChoice;
import tech.easyflow.ai.invoke.model.UnifiedContentPart;
import tech.easyflow.ai.invoke.model.UnifiedImageUrl;
import tech.easyflow.ai.invoke.model.UnifiedMessage;
import tech.easyflow.ai.invoke.model.UnifiedResponseFormat;
import tech.easyflow.ai.invoke.model.UnifiedTool;
import tech.easyflow.ai.invoke.model.UnifiedToolCall;
import tech.easyflow.ai.invoke.model.UnifiedToolCallFunction;
import tech.easyflow.ai.invoke.model.UnifiedToolFunction;
import tech.easyflow.ai.invoke.model.UnifiedUsage;
import tech.easyflow.ai.invoke.protocol.openai.OpenAiChatCompletionChunkResponse;
import tech.easyflow.ai.invoke.protocol.openai.OpenAiChatCompletionRequest;
import tech.easyflow.ai.invoke.protocol.openai.OpenAiChatCompletionResponse;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

@Component
public class OpenAiProtocolMapper {

    private static final Set<String> ROOT_FIELDS = Set.of(
            "model", "messages", "stream", "temperature", "top_p", "max_tokens",
            "seed", "tools", "tool_choice", "response_format"
    );
    private static final Set<String> MESSAGE_FIELDS = Set.of(
            "role", "content", "name", "tool_call_id", "tool_calls"
    );
    private static final Set<String> CONTENT_PART_FIELDS = Set.of("type", "text", "image_url");
    private static final Set<String> IMAGE_URL_FIELDS = Set.of("url", "detail");
    private static final Set<String> TOOL_FIELDS = Set.of("type", "function");
    private static final Set<String> TOOL_FUNCTION_FIELDS = Set.of("name", "description", "parameters");
    private static final Set<String> RESPONSE_FORMAT_FIELDS = Set.of("type", "json_schema");
    private static final Set<String> TOOL_CHOICE_FIELDS = Set.of("type", "function");

    private final ObjectMapper objectMapper;

    public OpenAiProtocolMapper(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
    }

    public OpenAiChatCompletionRequest readRequest(String rawBody) {
        JsonNode rootNode;
        try {
            rootNode = objectMapper.readTree(rawBody);
        } catch (JsonProcessingException e) {
            throw ModelInvokeException.badRequest("请求体不是合法 JSON", null, "invalid_json");
        }

        if (rootNode == null || !rootNode.isObject()) {
            throw ModelInvokeException.badRequest("请求体必须为 JSON 对象", null, "invalid_json");
        }
        validateAllowedFields(rootNode, ROOT_FIELDS, null);
        validateMessages(rootNode.path("messages"));
        validateTools(rootNode.path("tools"));
        validateToolChoice(rootNode.path("tool_choice"));
        validateResponseFormat(rootNode.path("response_format"));

        try {
            OpenAiChatCompletionRequest request = buildRequest(rootNode);
            if (StrUtil.isBlank(request.getModel())) {
                throw ModelInvokeException.badRequest("model 不能为空", "model", "model_required");
            }
            if (request.getMessages() == null || request.getMessages().isEmpty()) {
                throw ModelInvokeException.badRequest("messages 不能为空", "messages", "messages_required");
            }
            return request;
        } catch (IllegalArgumentException e) {
            throw ModelInvokeException.badRequest(e.getMessage(), "messages", "invalid_message_content");
        }
    }

    private OpenAiChatCompletionRequest buildRequest(JsonNode rootNode) {
        OpenAiChatCompletionRequest request = new OpenAiChatCompletionRequest();
        request.setModel(textValue(rootNode, "model"));
        request.setMessages(buildMessages(rootNode.path("messages")));
        if (rootNode.has("stream") && !rootNode.get("stream").isNull()) {
            request.setStream(rootNode.get("stream").asBoolean());
        }
        if (rootNode.has("temperature") && !rootNode.get("temperature").isNull()) {
            request.setTemperature(rootNode.get("temperature").asDouble());
        }
        if (rootNode.has("top_p") && !rootNode.get("top_p").isNull()) {
            request.setTopP(rootNode.get("top_p").asDouble());
        }
        if (rootNode.has("max_tokens") && !rootNode.get("max_tokens").isNull()) {
            request.setMaxTokens(rootNode.get("max_tokens").asInt());
        }
        if (rootNode.has("seed") && !rootNode.get("seed").isNull()) {
            request.setSeed(rootNode.get("seed").asLong());
        }
        if (rootNode.has("tools") && rootNode.get("tools").isArray()) {
            request.setTools(objectMapper.convertValue(
                    rootNode.get("tools"),
                    new TypeReference<>() {
                    }
            ));
        }
        if (rootNode.has("tool_choice") && !rootNode.get("tool_choice").isNull()) {
            request.setToolChoice(rootNode.get("tool_choice"));
        }
        if (rootNode.has("response_format") && rootNode.get("response_format").isObject()) {
            request.setResponseFormat(objectMapper.convertValue(
                    rootNode.get("response_format"),
                    OpenAiChatCompletionRequest.ResponseFormat.class
            ));
        }
        return request;
    }

    private List<OpenAiChatCompletionRequest.Message> buildMessages(JsonNode messagesNode) {
        List<OpenAiChatCompletionRequest.Message> messages = new ArrayList<>();
        for (JsonNode messageNode : messagesNode) {
            OpenAiChatCompletionRequest.Message message = new OpenAiChatCompletionRequest.Message();
            message.setRole(textValue(messageNode, "role"));
            if (messageNode.has("content")) {
                message.setContentNode(messageNode.get("content"));
            }
            message.setName(textValue(messageNode, "name"));
            message.setToolCallId(textValue(messageNode, "tool_call_id"));
            if (messageNode.has("tool_calls") && messageNode.get("tool_calls").isArray()) {
                message.setToolCalls(objectMapper.convertValue(
                        messageNode.get("tool_calls"),
                        new TypeReference<>() {
                        }
                ));
            }
            messages.add(message);
        }
        return messages;
    }

    public UnifiedChatRequest toUnifiedRequest(OpenAiChatCompletionRequest request) {
        UnifiedChatRequest unifiedRequest = new UnifiedChatRequest();
        unifiedRequest.setModel(request.getModel());
        unifiedRequest.setMessages(toUnifiedMessages(request.getMessages()));
        unifiedRequest.setStream(Boolean.TRUE.equals(request.getStream()));
        unifiedRequest.setTemperature(request.getTemperature());
        unifiedRequest.setTopP(request.getTopP());
        unifiedRequest.setMaxTokens(request.getMaxTokens());
        unifiedRequest.setSeed(request.getSeed());
        unifiedRequest.setTools(toUnifiedTools(request.getTools()));
        unifiedRequest.setToolChoice(request.getToolChoice());
        unifiedRequest.setResponseFormat(toUnifiedResponseFormat(request.getResponseFormat()));
        return unifiedRequest;
    }

    public OpenAiChatCompletionRequest toOpenAiRequest(UnifiedChatRequest request) {
        OpenAiChatCompletionRequest openAiRequest = new OpenAiChatCompletionRequest();
        openAiRequest.setModel(request.getModel());
        openAiRequest.setMessages(toOpenAiMessages(request.getMessages()));
        openAiRequest.setStream(request.getStream());
        openAiRequest.setTemperature(request.getTemperature());
        openAiRequest.setTopP(request.getTopP());
        openAiRequest.setMaxTokens(request.getMaxTokens());
        openAiRequest.setSeed(request.getSeed());
        openAiRequest.setTools(toOpenAiTools(request.getTools()));
        openAiRequest.setToolChoice(request.getToolChoice());
        openAiRequest.setResponseFormat(toOpenAiResponseFormat(request.getResponseFormat()));
        return openAiRequest;
    }

    public UnifiedChatResponse toUnifiedResponse(OpenAiChatCompletionResponse response) {
        UnifiedChatResponse unifiedResponse = new UnifiedChatResponse();
        unifiedResponse.setId(response.getId());
        unifiedResponse.setObject(response.getObject());
        unifiedResponse.setCreated(response.getCreated());
        unifiedResponse.setModel(response.getModel());
        unifiedResponse.setChoices(toUnifiedChoices(response.getChoices(), false));
        unifiedResponse.setUsage(toUnifiedUsage(response.getUsage()));
        return unifiedResponse;
    }

    public UnifiedChatChunk toUnifiedChunk(OpenAiChatCompletionChunkResponse chunk) {
        UnifiedChatChunk unifiedChunk = new UnifiedChatChunk();
        unifiedChunk.setId(chunk.getId());
        unifiedChunk.setObject(chunk.getObject());
        unifiedChunk.setCreated(chunk.getCreated());
        unifiedChunk.setModel(chunk.getModel());
        unifiedChunk.setChoices(toUnifiedChunkChoices(chunk.getChoices()));
        unifiedChunk.setUsage(toUnifiedUsage(chunk.getUsage()));
        return unifiedChunk;
    }

    public OpenAiChatCompletionResponse toOpenAiResponse(UnifiedChatResponse response) {
        OpenAiChatCompletionResponse openAiResponse = new OpenAiChatCompletionResponse();
        openAiResponse.setId(response.getId());
        openAiResponse.setObject(response.getObject());
        openAiResponse.setCreated(response.getCreated());
        openAiResponse.setModel(response.getModel());
        openAiResponse.setChoices(toOpenAiChoices(response.getChoices(), false));
        openAiResponse.setUsage(toOpenAiUsage(response.getUsage()));
        return openAiResponse;
    }

    public OpenAiChatCompletionChunkResponse toOpenAiChunk(UnifiedChatChunk chunk) {
        OpenAiChatCompletionChunkResponse openAiChunk = new OpenAiChatCompletionChunkResponse();
        openAiChunk.setId(chunk.getId());
        openAiChunk.setObject(chunk.getObject());
        openAiChunk.setCreated(chunk.getCreated());
        openAiChunk.setModel(chunk.getModel());
        openAiChunk.setChoices(toOpenAiChunkChoices(chunk.getChoices()));
        openAiChunk.setUsage(toOpenAiUsage(chunk.getUsage()));
        return openAiChunk;
    }

    private void validateMessages(JsonNode messagesNode) {
        if (messagesNode == null || !messagesNode.isArray() || messagesNode.isEmpty()) {
            throw ModelInvokeException.badRequest("messages 必须为非空数组", "messages", "messages_required");
        }
        for (int i = 0; i < messagesNode.size(); i++) {
            JsonNode messageNode = messagesNode.get(i);
            if (!messageNode.isObject()) {
                throw ModelInvokeException.badRequest("messages[" + i + "] 必须为对象", "messages", "invalid_message");
            }
            validateAllowedFields(messageNode, MESSAGE_FIELDS, "messages[" + i + "]");
            String role = textValue(messageNode, "role");
            if (!Set.of("system", "developer", "user", "assistant", "tool").contains(role)) {
                throw ModelInvokeException.badRequest("messages[" + i + "].role 不受支持", "messages", "invalid_message_role");
            }
            JsonNode contentNode = messageNode.get("content");
            if (contentNode != null && !contentNode.isNull() && !contentNode.isTextual() && !contentNode.isArray()) {
                throw ModelInvokeException.badRequest("messages[" + i + "].content 仅支持字符串或数组", "messages", "invalid_message_content");
            }
            if (contentNode != null && contentNode.isArray()) {
                validateContentParts(contentNode, "messages[" + i + "].content");
            }
        }
    }

    private void validateContentParts(JsonNode contentNode, String path) {
        for (int i = 0; i < contentNode.size(); i++) {
            JsonNode partNode = contentNode.get(i);
            if (!partNode.isObject()) {
                throw ModelInvokeException.badRequest(path + "[" + i + "] 必须为对象", "messages", "invalid_content_part");
            }
            validateAllowedFields(partNode, CONTENT_PART_FIELDS, path + "[" + i + "]");
            String type = textValue(partNode, "type");
            if (!Set.of("text", "image_url").contains(type)) {
                throw ModelInvokeException.badRequest(path + "[" + i + "].type 不受支持", "messages", "content_part_not_supported");
            }
            if ("text".equals(type) && StrUtil.isBlank(textValue(partNode, "text"))) {
                throw ModelInvokeException.badRequest(path + "[" + i + "].text 不能为空", "messages", "content_text_required");
            }
            if ("image_url".equals(type)) {
                JsonNode imageUrlNode = partNode.get("image_url");
                if (imageUrlNode == null || !imageUrlNode.isObject()) {
                    throw ModelInvokeException.badRequest(path + "[" + i + "].image_url 必须为对象", "messages", "image_url_required");
                }
                validateAllowedFields(imageUrlNode, IMAGE_URL_FIELDS, path + "[" + i + "].image_url");
                if (StrUtil.isBlank(textValue(imageUrlNode, "url"))) {
                    throw ModelInvokeException.badRequest(path + "[" + i + "].image_url.url 不能为空", "messages", "image_url_required");
                }
            }
        }
    }

    private void validateTools(JsonNode toolsNode) {
        if (isAbsentNode(toolsNode)) {
            return;
        }
        if (!toolsNode.isArray()) {
            throw ModelInvokeException.badRequest("tools 必须为数组", "tools", "invalid_tools");
        }
        for (int i = 0; i < toolsNode.size(); i++) {
            JsonNode toolNode = toolsNode.get(i);
            if (!toolNode.isObject()) {
                throw ModelInvokeException.badRequest("tools[" + i + "] 必须为对象", "tools", "invalid_tools");
            }
            validateAllowedFields(toolNode, TOOL_FIELDS, "tools[" + i + "]");
            JsonNode functionNode = toolNode.get("function");
            if (functionNode == null || !functionNode.isObject()) {
                throw ModelInvokeException.badRequest("tools[" + i + "].function 必须为对象", "tools", "invalid_tool_function");
            }
            validateAllowedFields(functionNode, TOOL_FUNCTION_FIELDS, "tools[" + i + "].function");
            if (StrUtil.isBlank(textValue(functionNode, "name"))) {
                throw ModelInvokeException.badRequest("tools[" + i + "].function.name 不能为空", "tools", "tool_name_required");
            }
        }
    }

    private void validateToolChoice(JsonNode toolChoiceNode) {
        if (isAbsentNode(toolChoiceNode)) {
            return;
        }
        if (toolChoiceNode.isTextual()) {
            return;
        }
        if (!toolChoiceNode.isObject()) {
            throw ModelInvokeException.badRequest("tool_choice 仅支持字符串或对象", "tool_choice", "invalid_tool_choice");
        }
        validateAllowedFields(toolChoiceNode, TOOL_CHOICE_FIELDS, "tool_choice");
    }

    private void validateResponseFormat(JsonNode responseFormatNode) {
        if (isAbsentNode(responseFormatNode)) {
            return;
        }
        if (!responseFormatNode.isObject()) {
            throw ModelInvokeException.badRequest("response_format 必须为对象", "response_format", "invalid_response_format");
        }
        validateAllowedFields(responseFormatNode, RESPONSE_FORMAT_FIELDS, "response_format");
        if (StrUtil.isBlank(textValue(responseFormatNode, "type"))) {
            throw ModelInvokeException.badRequest("response_format.type 不能为空", "response_format", "response_format_type_required");
        }
    }

    private boolean isAbsentNode(JsonNode node) {
        return node == null || node.isNull() || node.isMissingNode();
    }

    private void validateAllowedFields(JsonNode node, Set<String> allowedFields, String path) {
        Iterator<String> fieldNames = node.fieldNames();
        Set<String> unsupportedFields = new LinkedHashSet<>();
        while (fieldNames.hasNext()) {
            String fieldName = fieldNames.next();
            if (!allowedFields.contains(fieldName)) {
                unsupportedFields.add(path == null ? fieldName : path + "." + fieldName);
            }
        }
        if (!unsupportedFields.isEmpty()) {
            String field = unsupportedFields.iterator().next();
            throw ModelInvokeException.badRequest("存在未支持字段: " + field, field, "unsupported_field");
        }
    }

    private String textValue(JsonNode node, String fieldName) {
        JsonNode fieldNode = node.get(fieldName);
        if (fieldNode == null || fieldNode.isNull()) {
            return null;
        }
        return fieldNode.asText();
    }

    private List<UnifiedMessage> toUnifiedMessages(List<OpenAiChatCompletionRequest.Message> messages) {
        if (messages == null) {
            return null;
        }
        List<UnifiedMessage> result = new ArrayList<>();
        for (OpenAiChatCompletionRequest.Message message : messages) {
            UnifiedMessage unifiedMessage = new UnifiedMessage();
            unifiedMessage.setRole(message.getRole());
            unifiedMessage.setContent(message.getContent());
            unifiedMessage.setContentParts(toUnifiedContentParts(message.getContentParts()));
            unifiedMessage.setName(message.getName());
            unifiedMessage.setToolCallId(message.getToolCallId());
            unifiedMessage.setToolCalls(toUnifiedToolCalls(message.getToolCalls()));
            result.add(unifiedMessage);
        }
        return result;
    }

    private List<OpenAiChatCompletionRequest.Message> toOpenAiMessages(List<UnifiedMessage> messages) {
        if (messages == null) {
            return null;
        }
        List<OpenAiChatCompletionRequest.Message> result = new ArrayList<>();
        for (UnifiedMessage message : messages) {
            OpenAiChatCompletionRequest.Message openAiMessage = new OpenAiChatCompletionRequest.Message();
            openAiMessage.setRole(message.getRole());
            if (message.getContentParts() != null && !message.getContentParts().isEmpty()) {
                ObjectNode contentNode = objectMapper.createObjectNode();
                contentNode.set("content", objectMapper.valueToTree(toOpenAiContentParts(message.getContentParts())));
                openAiMessage.setContentNode(contentNode.get("content"));
            } else {
                ObjectNode contentNode = objectMapper.createObjectNode();
                if (message.getContent() == null) {
                    contentNode.putNull("content");
                } else {
                    contentNode.put("content", message.getContent());
                }
                openAiMessage.setContentNode(contentNode.get("content"));
            }
            openAiMessage.setName(message.getName());
            openAiMessage.setToolCallId(message.getToolCallId());
            openAiMessage.setToolCalls(toOpenAiToolCalls(message.getToolCalls()));
            result.add(openAiMessage);
        }
        return result;
    }

    private List<UnifiedContentPart> toUnifiedContentParts(List<OpenAiChatCompletionRequest.ContentPart> contentParts) {
        if (contentParts == null) {
            return null;
        }
        List<UnifiedContentPart> result = new ArrayList<>();
        for (OpenAiChatCompletionRequest.ContentPart contentPart : contentParts) {
            UnifiedContentPart unifiedContentPart = new UnifiedContentPart();
            unifiedContentPart.setType(contentPart.getType());
            unifiedContentPart.setText(contentPart.getText());
            if (contentPart.getImageUrl() != null) {
                UnifiedImageUrl imageUrl = new UnifiedImageUrl();
                imageUrl.setUrl(contentPart.getImageUrl().getUrl());
                imageUrl.setDetail(contentPart.getImageUrl().getDetail());
                unifiedContentPart.setImageUrl(imageUrl);
            }
            result.add(unifiedContentPart);
        }
        return result;
    }

    private List<OpenAiChatCompletionRequest.ContentPart> toOpenAiContentParts(List<UnifiedContentPart> contentParts) {
        if (contentParts == null) {
            return null;
        }
        List<OpenAiChatCompletionRequest.ContentPart> result = new ArrayList<>();
        for (UnifiedContentPart contentPart : contentParts) {
            OpenAiChatCompletionRequest.ContentPart openAiPart = new OpenAiChatCompletionRequest.ContentPart();
            openAiPart.setType(contentPart.getType());
            openAiPart.setText(contentPart.getText());
            if (contentPart.getImageUrl() != null) {
                OpenAiChatCompletionRequest.ImageUrl imageUrl = new OpenAiChatCompletionRequest.ImageUrl();
                imageUrl.setUrl(contentPart.getImageUrl().getUrl());
                imageUrl.setDetail(contentPart.getImageUrl().getDetail());
                openAiPart.setImageUrl(imageUrl);
            }
            result.add(openAiPart);
        }
        return result;
    }

    private List<UnifiedTool> toUnifiedTools(List<OpenAiChatCompletionRequest.Tool> tools) {
        if (tools == null) {
            return null;
        }
        List<UnifiedTool> result = new ArrayList<>();
        for (OpenAiChatCompletionRequest.Tool tool : tools) {
            UnifiedTool unifiedTool = new UnifiedTool();
            unifiedTool.setType(tool.getType());
            if (tool.getFunction() != null) {
                UnifiedToolFunction function = new UnifiedToolFunction();
                function.setName(tool.getFunction().getName());
                function.setDescription(tool.getFunction().getDescription());
                function.setParameters(tool.getFunction().getParameters());
                unifiedTool.setFunction(function);
            }
            result.add(unifiedTool);
        }
        return result;
    }

    private List<OpenAiChatCompletionRequest.Tool> toOpenAiTools(List<UnifiedTool> tools) {
        if (tools == null) {
            return null;
        }
        List<OpenAiChatCompletionRequest.Tool> result = new ArrayList<>();
        for (UnifiedTool tool : tools) {
            OpenAiChatCompletionRequest.Tool openAiTool = new OpenAiChatCompletionRequest.Tool();
            openAiTool.setType(tool.getType());
            if (tool.getFunction() != null) {
                OpenAiChatCompletionRequest.ToolFunction function = new OpenAiChatCompletionRequest.ToolFunction();
                function.setName(tool.getFunction().getName());
                function.setDescription(tool.getFunction().getDescription());
                function.setParameters(tool.getFunction().getParameters());
                openAiTool.setFunction(function);
            }
            result.add(openAiTool);
        }
        return result;
    }

    private UnifiedResponseFormat toUnifiedResponseFormat(OpenAiChatCompletionRequest.ResponseFormat responseFormat) {
        if (responseFormat == null) {
            return null;
        }
        UnifiedResponseFormat unifiedResponseFormat = new UnifiedResponseFormat();
        unifiedResponseFormat.setType(responseFormat.getType());
        unifiedResponseFormat.setJsonSchema(responseFormat.getJsonSchema());
        return unifiedResponseFormat;
    }

    private OpenAiChatCompletionRequest.ResponseFormat toOpenAiResponseFormat(UnifiedResponseFormat responseFormat) {
        if (responseFormat == null) {
            return null;
        }
        OpenAiChatCompletionRequest.ResponseFormat openAiResponseFormat = new OpenAiChatCompletionRequest.ResponseFormat();
        openAiResponseFormat.setType(responseFormat.getType());
        openAiResponseFormat.setJsonSchema(responseFormat.getJsonSchema());
        return openAiResponseFormat;
    }

    private List<UnifiedChoice> toUnifiedChoices(List<OpenAiChatCompletionResponse.Choice> choices, boolean delta) {
        if (choices == null) {
            return null;
        }
        List<UnifiedChoice> result = new ArrayList<>();
        for (OpenAiChatCompletionResponse.Choice choice : choices) {
            UnifiedChoice unifiedChoice = new UnifiedChoice();
            unifiedChoice.setIndex(choice.getIndex());
            UnifiedMessage message = new UnifiedMessage();
            if (choice.getMessage() != null) {
                message.setRole(choice.getMessage().getRole());
                message.setContent(choice.getMessage().getContent());
                message.setToolCallId(choice.getMessage().getToolCallId());
                message.setToolCalls(toUnifiedToolCalls(choice.getMessage().getToolCalls()));
            }
            if (delta) {
                unifiedChoice.setDelta(message);
            } else {
                unifiedChoice.setMessage(message);
            }
            unifiedChoice.setFinishReason(choice.getFinishReason());
            result.add(unifiedChoice);
        }
        return result;
    }

    private List<UnifiedChoice> toUnifiedChunkChoices(List<OpenAiChatCompletionChunkResponse.Choice> choices) {
        if (choices == null) {
            return null;
        }
        List<UnifiedChoice> result = new ArrayList<>();
        for (OpenAiChatCompletionChunkResponse.Choice choice : choices) {
            UnifiedChoice unifiedChoice = new UnifiedChoice();
            unifiedChoice.setIndex(choice.getIndex());
            UnifiedMessage delta = new UnifiedMessage();
            if (choice.getDelta() != null) {
                delta.setRole(choice.getDelta().getRole());
                delta.setContent(choice.getDelta().getContent());
                delta.setToolCalls(toUnifiedToolCalls(choice.getDelta().getToolCalls()));
            }
            unifiedChoice.setDelta(delta);
            unifiedChoice.setFinishReason(choice.getFinishReason());
            result.add(unifiedChoice);
        }
        return result;
    }

    private List<OpenAiChatCompletionResponse.Choice> toOpenAiChoices(List<UnifiedChoice> choices, boolean delta) {
        if (choices == null) {
            return null;
        }
        List<OpenAiChatCompletionResponse.Choice> result = new ArrayList<>();
        for (UnifiedChoice choice : choices) {
            OpenAiChatCompletionResponse.Choice openAiChoice = new OpenAiChatCompletionResponse.Choice();
            openAiChoice.setIndex(choice.getIndex());
            UnifiedMessage source = delta ? choice.getDelta() : choice.getMessage();
            if (source != null) {
                OpenAiChatCompletionResponse.Message message = new OpenAiChatCompletionResponse.Message();
                message.setRole(source.getRole());
                message.setContent(source.getContent());
                message.setToolCallId(source.getToolCallId());
                message.setToolCalls(toOpenAiToolCalls(source.getToolCalls()));
                openAiChoice.setMessage(message);
            }
            openAiChoice.setFinishReason(choice.getFinishReason());
            result.add(openAiChoice);
        }
        return result;
    }

    private List<OpenAiChatCompletionChunkResponse.Choice> toOpenAiChunkChoices(List<UnifiedChoice> choices) {
        if (choices == null) {
            return null;
        }
        List<OpenAiChatCompletionChunkResponse.Choice> result = new ArrayList<>();
        for (UnifiedChoice choice : choices) {
            OpenAiChatCompletionChunkResponse.Choice openAiChoice = new OpenAiChatCompletionChunkResponse.Choice();
            openAiChoice.setIndex(choice.getIndex());
            if (choice.getDelta() != null) {
                OpenAiChatCompletionChunkResponse.Delta delta = new OpenAiChatCompletionChunkResponse.Delta();
                delta.setRole(choice.getDelta().getRole());
                delta.setContent(choice.getDelta().getContent());
                delta.setToolCalls(toOpenAiToolCalls(choice.getDelta().getToolCalls()));
                openAiChoice.setDelta(delta);
            }
            openAiChoice.setFinishReason(choice.getFinishReason());
            result.add(openAiChoice);
        }
        return result;
    }

    private List<UnifiedToolCall> toUnifiedToolCalls(List<OpenAiChatCompletionResponse.ToolCall> toolCalls) {
        if (toolCalls == null) {
            return null;
        }
        List<UnifiedToolCall> result = new ArrayList<>();
        for (OpenAiChatCompletionResponse.ToolCall toolCall : toolCalls) {
            UnifiedToolCall unifiedToolCall = new UnifiedToolCall();
            unifiedToolCall.setIndex(toolCall.getIndex());
            unifiedToolCall.setId(toolCall.getId());
            unifiedToolCall.setType(toolCall.getType());
            if (toolCall.getFunction() != null) {
                UnifiedToolCallFunction function = new UnifiedToolCallFunction();
                function.setName(toolCall.getFunction().getName());
                function.setArguments(toolCall.getFunction().getArguments());
                unifiedToolCall.setFunction(function);
            }
            result.add(unifiedToolCall);
        }
        return result;
    }

    private List<OpenAiChatCompletionResponse.ToolCall> toOpenAiToolCalls(List<UnifiedToolCall> toolCalls) {
        if (toolCalls == null) {
            return null;
        }
        List<OpenAiChatCompletionResponse.ToolCall> result = new ArrayList<>();
        for (UnifiedToolCall toolCall : toolCalls) {
            OpenAiChatCompletionResponse.ToolCall openAiToolCall = new OpenAiChatCompletionResponse.ToolCall();
            openAiToolCall.setIndex(toolCall.getIndex());
            openAiToolCall.setId(toolCall.getId());
            openAiToolCall.setType(toolCall.getType());
            if (toolCall.getFunction() != null) {
                OpenAiChatCompletionResponse.ToolCallFunction function = new OpenAiChatCompletionResponse.ToolCallFunction();
                function.setName(toolCall.getFunction().getName());
                function.setArguments(toolCall.getFunction().getArguments());
                openAiToolCall.setFunction(function);
            }
            result.add(openAiToolCall);
        }
        return result;
    }

    private UnifiedUsage toUnifiedUsage(OpenAiChatCompletionResponse.Usage usage) {
        if (usage == null) {
            return null;
        }
        UnifiedUsage unifiedUsage = new UnifiedUsage();
        unifiedUsage.setPromptTokens(usage.getPromptTokens());
        unifiedUsage.setCompletionTokens(usage.getCompletionTokens());
        unifiedUsage.setTotalTokens(usage.getTotalTokens());
        return unifiedUsage;
    }

    private OpenAiChatCompletionResponse.Usage toOpenAiUsage(UnifiedUsage usage) {
        if (usage == null) {
            return null;
        }
        OpenAiChatCompletionResponse.Usage openAiUsage = new OpenAiChatCompletionResponse.Usage();
        openAiUsage.setPromptTokens(usage.getPromptTokens());
        openAiUsage.setCompletionTokens(usage.getCompletionTokens());
        openAiUsage.setTotalTokens(usage.getTotalTokens());
        return openAiUsage;
    }
}
