import { getLogger as getLogger$1 } from "../../../logger.js";
import { ImageUrlSchema, VercelContentPartSchema } from "../types/chat.js";
import { FilePartSchema, TextPartSchema } from "@inkeep/agents-core";

//#region src/domains/run/utils/message-parts.ts
const logger = getLogger$1("message-parts");
const isTextContentItem = (item) => {
	return item.type === "text" && "text" in item && typeof item.text === "string";
};
const isImageContentItem = (item) => {
	return item.type === "image_url" && "image_url" in item && item.image_url != null && ImageUrlSchema.safeParse(item.image_url.url).success;
};
const isFileContentItem = (item) => {
	return item.type === "file";
};
const buildTextPart = (text) => {
	return TextPartSchema.parse({
		kind: "text",
		text
	});
};
const parseDataUri = (dataUri) => {
	const match = dataUri.match(/^data:([^;]+);base64,(.+)$/);
	if (!match) return null;
	return {
		mimeType: match[1],
		base64Data: match[2]
	};
};
const buildFilePart = (uri, options) => {
	const parsed = parseDataUri(uri);
	if (parsed) {
		const metadata$1 = {};
		if (options?.detail) metadata$1.detail = options.detail;
		if (options?.filename) metadata$1.filename = options.filename;
		return FilePartSchema.parse({
			kind: "file",
			file: {
				bytes: parsed.base64Data,
				mimeType: parsed.mimeType
			},
			...Object.keys(metadata$1).length > 0 ? { metadata: metadata$1 } : {}
		});
	}
	try {
		new URL(uri);
	} catch {
		throw new Error(`Invalid file URI: expected valid data URI or HTTP URL`);
	}
	const metadata = {};
	if (options?.detail) metadata.detail = options.detail;
	if (options?.filename) metadata.filename = options.filename;
	return FilePartSchema.parse({
		kind: "file",
		file: {
			uri,
			mimeType: options?.mimeType || "application/octet-stream"
		},
		...Object.keys(metadata).length > 0 ? { metadata } : {}
	});
};
const extractTextFromParts = (parts) => {
	return parts.filter((p) => p.kind === "text").map((p) => p.text).join(" ");
};
const getMessagePartsFromOpenAIContent = (content) => {
	if (typeof content === "string") return [buildTextPart(content)];
	const textChunks = [];
	const fileParts = [];
	let skipped = 0;
	for (const item of content) if (isTextContentItem(item)) textChunks.push(item.text);
	else if (isImageContentItem(item)) fileParts.push(buildFilePart(item.image_url.url, { detail: item.image_url.detail }));
	else if (isFileContentItem(item)) fileParts.push(buildFilePart(item.file.file_data, {
		filename: item.file.filename,
		mimeType: "application/pdf"
	}));
	else skipped += 1;
	if (skipped > 0) logger.warn({
		total: content.length,
		skipped,
		accepted: content.length - skipped
	}, "Some content items were dropped due to invalid or unsupported type");
	return [...textChunks.length > 0 ? [buildTextPart(textChunks.join(" "))] : [], ...fileParts];
};
const getMessagePartsFromVercelContent = (content, parts) => {
	const rawParts = parts ?? [];
	const parsedParts = rawParts.map((part) => VercelContentPartSchema.safeParse(part)).filter((result) => result.success).map((result) => result.data);
	if (parsedParts.length < rawParts.length) logger.warn({
		expected: rawParts.length,
		received: parsedParts.length
	}, "Some message parts were dropped due to invalid schema");
	const assertNever = (x) => {
		throw new Error(`Unexpected part type: ${JSON.stringify(x)}`);
	};
	const partsFromPayload = parsedParts.map((part) => {
		if (part.type === "text") return buildTextPart(part.text);
		if (part.type === "image") return buildFilePart(part.text);
		if (part.type === "file") return buildFilePart(part.url, {
			mimeType: part.mediaType,
			filename: part.filename
		});
		return assertNever(part);
	});
	if (typeof content !== "string" || content === "") return partsFromPayload;
	const contentTextPart = buildTextPart(content);
	const firstPartsText = partsFromPayload.find((part) => part.kind === "text")?.text;
	const hasMatchingTextPart = partsFromPayload.some((part) => part.kind === "text" && part.text === content);
	if (firstPartsText != null && firstPartsText !== content) logger.warn({
		contentText: content,
		firstPartsText,
		partsCount: partsFromPayload.length
	}, "Both content and parts text were provided and differ; prepending content text");
	if (hasMatchingTextPart) return partsFromPayload;
	return [contentTextPart, ...partsFromPayload];
};

//#endregion
export { extractTextFromParts, getMessagePartsFromOpenAIContent, getMessagePartsFromVercelContent };