import { isRecord } from "../../utils/types.js";
import { extractInputTokenDetails, extractOutputTokenDetails, } from "../../utils/vercel.js";
const guessMimetypeFromBase64 = (data) => {
    // Check magic bytes from base64 data
    const bytes = atob(data.substring(0, 20)); // Decode first few bytes
    // PNG: 89 50 4E 47
    if (bytes.charCodeAt(0) === 0x89 &&
        bytes.charCodeAt(1) === 0x50 &&
        bytes.charCodeAt(2) === 0x4e &&
        bytes.charCodeAt(3) === 0x47) {
        return "image/png";
    }
    // JPEG: FF D8 FF
    if (bytes.charCodeAt(0) === 0xff &&
        bytes.charCodeAt(1) === 0xd8 &&
        bytes.charCodeAt(2) === 0xff) {
        return "image/jpeg";
    }
    // GIF: 47 49 46 38
    if (bytes.charCodeAt(0) === 0x47 &&
        bytes.charCodeAt(1) === 0x49 &&
        bytes.charCodeAt(2) === 0x46 &&
        bytes.charCodeAt(3) === 0x38) {
        return "image/gif";
    }
    // WebP: 52 49 46 46 (RIFF) ... 57 45 42 50 (WEBP)
    if (bytes.charCodeAt(0) === 0x52 &&
        bytes.charCodeAt(1) === 0x49 &&
        bytes.charCodeAt(2) === 0x46 &&
        bytes.charCodeAt(3) === 0x46) {
        if (bytes.indexOf("WEBP") !== -1) {
            return "image/webp";
        }
    }
    // PDF: 25 50 44 46 (%PDF)
    if (bytes.charCodeAt(0) === 0x25 &&
        bytes.charCodeAt(1) === 0x50 &&
        bytes.charCodeAt(2) === 0x44 &&
        bytes.charCodeAt(3) === 0x46) {
        return "application/pdf";
    }
    return undefined;
};
function _isAISDKFileData(input) {
    if (!isRecord(input))
        return false;
    if (input.type === "data" && "data" in input)
        return true;
    if (input.type === "url" && "url" in input)
        return true;
    if (input.type === "reference" && "reference" in input)
        return true;
    if (input.type === "text" && "text" in input)
        return true;
    return false;
}
function _toUint8Array(fileData) {
    // Covers `fileData: ArrayBuffer | Buffer | Uint8Array`
    if (fileData instanceof Uint8Array) {
        return fileData;
    }
    if (fileData != null &&
        typeof fileData === "object" &&
        "type" in fileData &&
        "data" in fileData &&
        typeof fileData.data === "object" &&
        // eslint-disable-next-line no-instanceof/no-instanceof
        fileData.data instanceof Uint8Array) {
        return fileData.data;
        // eslint-disable-next-line no-instanceof/no-instanceof
    }
    if (fileData instanceof ArrayBuffer) {
        return new Uint8Array(fileData);
    }
    return undefined;
}
export const normalizeFileDataAsDataURL = (fileData, mimeType) => {
    if (_isAISDKFileData(fileData)) {
        if (fileData.type === "data") {
            return normalizeFileDataAsDataURL(fileData.data, mimeType);
        }
        if (fileData.type === "url") {
            return fileData.url.toString();
        }
        if (fileData.type === "reference") {
            // TODO: figure out if we can store the reference in a more reasonable format
            return `data:application/octet-stream;base64,${btoa(JSON.stringify(fileData.reference))}`;
        }
        if (fileData.type === "text") {
            return `data:text/plain;base64,${btoa(fileData.text)}`;
        }
        throw new Error("AISDKFileData is not supported");
    }
    if (fileData instanceof URL) {
        return fileData.toString();
    }
    if (typeof fileData !== "string") {
        const uint8Array = _toUint8Array(fileData);
        if (uint8Array) {
            let binary = "";
            for (let i = 0; i < uint8Array.length; i++) {
                binary += String.fromCharCode(uint8Array[i]);
            }
            const base64 = btoa(binary);
            const dataType = mimeType ??
                guessMimetypeFromBase64(base64) ??
                "application/octet-stream";
            return `data:${dataType};base64,${base64}`;
        }
    }
    if (typeof fileData === "string") {
        if (fileData.startsWith("http://") || fileData.startsWith("https://")) {
            return fileData;
        }
        if (!fileData.startsWith("data:")) {
            return `data:${mimeType ??
                guessMimetypeFromBase64(fileData) ??
                "application/octet-stream"};base64,${fileData}`;
        }
        return fileData;
    }
    return "";
};
export const convertMessageToTracedFormat = (rawMessage, responseMetadata) => {
    const message = rawMessage;
    const formattedMessage = {
        ...message,
    };
    if (Array.isArray(message.content)) {
        if (message.role === "assistant") {
            const toolCallBlocks = message.content.filter((block) => {
                return (block != null &&
                    typeof block === "object" &&
                    block.type === "tool-call");
            });
            const toolCalls = toolCallBlocks.map((block) => {
                // AI SDK 4 shim
                let toolArgs = block.input ?? (("args" in block && block.args) || undefined);
                if (typeof toolArgs !== "string") {
                    toolArgs = JSON.stringify(toolArgs);
                }
                return {
                    id: block.toolCallId,
                    type: "function",
                    function: {
                        name: block.toolName,
                        arguments: toolArgs,
                    },
                };
            });
            if (toolCalls.length > 0) {
                formattedMessage.tool_calls = toolCalls;
            }
        }
        const newContent = message.content.map((part) => {
            if (part.type === "file") {
                const { data, mediaType, filename, ...rest } = part;
                return {
                    ...rest,
                    file: {
                        filename,
                        file_data: normalizeFileDataAsDataURL(data, mediaType),
                    },
                };
            }
            else if (part.type === "image") {
                const { image, mediaType, ...rest } = part;
                return {
                    ...rest,
                    type: "image_url",
                    image_url: normalizeFileDataAsDataURL(image, mediaType),
                };
            }
            else if (part.type === "reasoning" &&
                "text" in part &&
                typeof part.text === "string") {
                return {
                    type: "reasoning",
                    reasoning: part.text,
                };
            }
            return part;
        });
        formattedMessage.content = newContent;
    }
    else if (message.content == null && "text" in message) {
        // AI SDK 4 shim
        formattedMessage.content = message.text ?? "";
        if ("toolCalls" in message &&
            Array.isArray(message.toolCalls) &&
            !("tool_calls" in formattedMessage)) {
            formattedMessage.tool_calls = message.toolCalls.map((toolCall) => {
                return {
                    id: toolCall.toolCallId,
                    type: "function",
                    function: { name: toolCall.toolName, arguments: toolCall.args },
                };
            });
        }
    }
    if (responseMetadata != null) {
        formattedMessage.response_metadata = responseMetadata;
    }
    return formattedMessage;
};
export const setUsageMetadataOnRunTree = (result, runTree) => {
    if (result.usage == null || typeof result.usage !== "object") {
        return;
    }
    const usage = result.usage;
    let inputTokens;
    let outputTokens;
    let totalTokens;
    // AI SDK 6: Check for object-based token structures first
    if (isRecord(usage.inputTokens) &&
        usage.inputTokens?.total != null &&
        typeof usage.inputTokens.total === "number") {
        // AI SDK 6 detected
        inputTokens = usage.inputTokens.total;
        if (isRecord(usage.outputTokens) &&
            usage.outputTokens?.total != null &&
            typeof usage.outputTokens.total === "number") {
            outputTokens = usage.outputTokens.total;
        }
        totalTokens = result.usage?.totalTokens;
        if (typeof totalTokens !== "number" &&
            typeof inputTokens === "number" &&
            typeof outputTokens === "number") {
            totalTokens = inputTokens + outputTokens;
        }
    }
    else if (typeof usage.inputTokens === "number") {
        // AI SDK 5 detected
        inputTokens = usage.inputTokens;
        if (typeof usage.outputTokens === "number") {
            outputTokens = usage.outputTokens;
        }
        totalTokens = result.usage?.totalTokens;
        if (typeof totalTokens !== "number" &&
            typeof inputTokens === "number" &&
            typeof outputTokens === "number") {
            totalTokens = inputTokens + outputTokens;
        }
    }
    else {
        // AI SDK 4 fallback
        if (typeof usage.promptTokens === "number") {
            inputTokens = usage.promptTokens;
        }
        if (typeof usage.completionTokens === "number") {
            outputTokens = usage.completionTokens;
        }
        totalTokens = result.usage?.totalTokens;
        if (typeof totalTokens !== "number" &&
            typeof inputTokens === "number" &&
            typeof outputTokens === "number") {
            totalTokens = inputTokens + outputTokens;
        }
    }
    const langsmithUsage = {
        input_tokens: inputTokens,
        output_tokens: outputTokens,
        total_tokens: totalTokens,
    };
    const inputTokenDetails = extractInputTokenDetails(result.usage, result.providerMetadata);
    const outputTokenDetails = extractOutputTokenDetails(result.usage, result.providerMetadata);
    runTree.extra = {
        ...runTree.extra,
        metadata: {
            ...runTree.extra?.metadata,
            usage_metadata: {
                ...langsmithUsage,
                input_token_details: {
                    ...inputTokenDetails,
                },
                output_token_details: {
                    ...outputTokenDetails,
                },
            },
        },
    };
};
