import { isTextDocumentMimeType } from "../utils/text-document-attachments.js";
import { z } from "@hono/zod-openapi";
import { DATA_URI_IMAGE_BASE64_REGEX, DATA_URI_OFFICE_BASE64_REGEX, DATA_URI_PDF_BASE64_REGEX, DATA_URI_TEXT_BASE64_REGEX, ZIP_DOCUMENT_EXTENSIONS_LABEL, canonicalizeMimeType, isOfficeDocumentMimeType, normalizeMimeType } from "@inkeep/agents-core/constants/allowed-file-formats";

//#region src/domains/run/types/chat.ts
const rewriteDataUriMimeType = (dataUri, mimeType) => dataUri.replace(/^(data:)[^;,]*/i, `$1${mimeType}`);
const extractDataUriMimeType = (dataUri) => /^data:([^;,]+)/i.exec(dataUri)?.[1] ?? "";
const preprocessFileObject = (val) => {
	if (!val || typeof val !== "object") return val;
	const obj = val;
	if (typeof obj.file_data !== "string" || !obj.file_data.startsWith("data:")) return val;
	const filename = typeof obj.filename === "string" ? obj.filename : void 0;
	const incoming = extractDataUriMimeType(obj.file_data);
	const canonical = canonicalizeMimeType(incoming, filename);
	if (canonical === normalizeMimeType(incoming)) return val;
	return {
		...obj,
		file_data: rewriteDataUriMimeType(obj.file_data, canonical)
	};
};
const preprocessVercelFilePart = (val) => {
	if (!val || typeof val !== "object") return val;
	const obj = val;
	const filename = typeof obj.filename === "string" ? obj.filename : void 0;
	const incomingMime = typeof obj.mediaType === "string" ? obj.mediaType : "";
	const dataUriMime = typeof obj.url === "string" && obj.url.startsWith("data:") ? extractDataUriMimeType(obj.url) : "";
	const normalizedIncomingMime = normalizeMimeType(incomingMime);
	const canonical = canonicalizeMimeType(incomingMime || dataUriMime, filename);
	const url = typeof obj.url === "string" && obj.url.startsWith("data:") && canonical.length > 0 && canonical !== normalizeMimeType(dataUriMime) ? rewriteDataUriMimeType(obj.url, canonical) : obj.url;
	if (canonical === normalizedIncomingMime && url === obj.url) return val;
	return {
		...obj,
		mediaType: canonical,
		url
	};
};
const hasValidBase64Payload = (val) => {
	const base64Part = val.split(",")[1];
	return /^[A-Za-z0-9+/]+={0,2}$/.test(base64Part ?? "");
};
const ImageDataUriSchema = z.string().regex(DATA_URI_IMAGE_BASE64_REGEX, "Image must be PNG, JPEG, or WebP format (GIF not supported by all providers)").refine(hasValidBase64Payload, "Invalid base64 data in image data URI");
const PdfDataUriSchema = z.string().regex(DATA_URI_PDF_BASE64_REGEX, "File must be a PDF data URI").refine(hasValidBase64Payload, "Invalid base64 data in PDF data URI");
const normalizeDataUriMimeType = (val) => {
	if (typeof val !== "string") return val;
	return val.replace(/^(data:)([^;,]+)/i, (_, prefix, mimeType) => `${prefix}${mimeType.toLowerCase()}`);
};
const TextDocumentDataUriSchema = z.preprocess(normalizeDataUriMimeType, z.string().regex(DATA_URI_TEXT_BASE64_REGEX, "File must be a supported text/code document data URI").refine(hasValidBase64Payload, "Invalid base64 data in text document data URI"));
const ImageUrlSchema = z.union([z.httpUrl(), ImageDataUriSchema]);
const OFFICE_DOCUMENT_DATA_URI_MESSAGE = `File must be a supported ZIP-based document data URI (${ZIP_DOCUMENT_EXTENSIONS_LABEL})`;
const INVALID_OFFICE_DOCUMENT_DATA_URI_BASE64_MESSAGE = `Invalid base64 data in ZIP-based document data URI (${ZIP_DOCUMENT_EXTENSIONS_LABEL})`;
const getDataUriMimeType = (val) => normalizeMimeType(/^data:([^;,]+)/i.exec(val)?.[1] ?? "");
const getFirstIssueMessage = (issues) => {
	if (!Array.isArray(issues)) return void 0;
	for (const issue of issues) if (issue && typeof issue === "object" && "message" in issue && typeof issue.message === "string" && issue.message !== "Invalid input") return issue.message;
};
const getInlineDocumentUnionErrorMessage = (issue) => {
	if (issue.code !== "invalid_union" || typeof issue.input !== "string") return;
	const mimeType = getDataUriMimeType(issue.input);
	if (!mimeType) return;
	if (mimeType === "application/zip" || isOfficeDocumentMimeType(mimeType)) return getFirstIssueMessage(Array.isArray(issue.errors) ? issue.errors[2] : void 0) ?? OFFICE_DOCUMENT_DATA_URI_MESSAGE;
};
const OfficeDocumentDataUriSchema = z.preprocess(normalizeDataUriMimeType, z.string().regex(DATA_URI_OFFICE_BASE64_REGEX, OFFICE_DOCUMENT_DATA_URI_MESSAGE).refine(hasValidBase64Payload, INVALID_OFFICE_DOCUMENT_DATA_URI_BASE64_MESSAGE));
const PdfDataOrUrlSchema = z.union([PdfDataUriSchema, z.httpUrl()]);
const InlineDocumentDataSchema = z.union([
	PdfDataOrUrlSchema,
	TextDocumentDataUriSchema,
	OfficeDocumentDataUriSchema
], { error: getInlineDocumentUnionErrorMessage });
/** OpenAI-specific image detail level. Has no effect on other providers. */
const ImageDetailEnum = [
	"auto",
	"low",
	"high"
];
const ImageDetailSchema = z.enum(ImageDetailEnum);
const ImageContentItemSchema = z.object({
	type: z.literal("image_url"),
	image_url: z.object({
		url: ImageUrlSchema,
		detail: ImageDetailSchema.optional()
	})
});
const FileContentItemSchema = z.object({
	type: z.literal("file"),
	file: z.preprocess(preprocessFileObject, z.object({
		file_data: InlineDocumentDataSchema,
		filename: z.string().optional()
	}))
});
const VercelTextPartSchema = z.object({
	type: z.literal("text"),
	text: z.string()
});
const VercelImagePartSchema = z.object({
	type: z.literal("image"),
	text: ImageUrlSchema
});
const VercelFilePartSchema = z.preprocess(preprocessVercelFilePart, z.object({
	type: z.literal("file"),
	url: z.string(),
	mediaType: z.string(),
	filename: z.string().optional()
}).superRefine((part, ctx) => {
	const mimeType = normalizeMimeType(part.mediaType);
	const normalizedUrl = normalizeDataUriMimeType(part.url);
	if (isTextDocumentMimeType(mimeType) && !DATA_URI_TEXT_BASE64_REGEX.test(normalizedUrl)) ctx.addIssue({
		code: z.ZodIssueCode.custom,
		message: "Text document file parts must use inline base64 data URIs",
		path: ["url"]
	});
	if (isOfficeDocumentMimeType(mimeType) && !DATA_URI_OFFICE_BASE64_REGEX.test(normalizedUrl)) ctx.addIssue({
		code: z.ZodIssueCode.custom,
		message: `ZIP-based document file parts (${ZIP_DOCUMENT_EXTENSIONS_LABEL}) must use inline base64 data URIs`,
		path: ["url"]
	});
}));
const VercelAudioVideoPartSchema = z.object({
	type: z.union([z.enum(["audio", "video"]), z.string().regex(/^data-/, "Type must start with \"data-\"")]),
	text: z.string().optional()
});
const VercelToolApprovalPartSchema = z.object({
	type: z.string().regex(/^tool-/, "Type must start with \"tool-\""),
	toolCallId: z.string(),
	state: z.any(),
	approval: z.object({
		id: z.string(),
		approved: z.boolean().optional(),
		reason: z.string().optional()
	}).optional(),
	input: z.any().optional(),
	callProviderMetadata: z.any().optional()
});
const VercelStepStartPartSchema = z.object({ type: z.literal("step-start") });
const VercelMessagePartSchema = z.union([
	VercelTextPartSchema,
	VercelImagePartSchema,
	VercelFilePartSchema,
	VercelAudioVideoPartSchema,
	VercelToolApprovalPartSchema,
	VercelStepStartPartSchema
]);
const MessageIdSchema = z.string().regex(/^[A-Za-z0-9_-]+$/).min(1).max(64);
const VercelMessageSchema = z.object({
	id: MessageIdSchema.optional(),
	role: z.enum([
		"system",
		"user",
		"assistant",
		"function",
		"tool"
	]),
	content: z.any(),
	parts: z.array(VercelMessagePartSchema).optional()
});
const VercelContentPartSchema = z.union([
	VercelTextPartSchema,
	VercelImagePartSchema,
	VercelFilePartSchema
]);
const ContentItemSchema = z.union([
	VercelTextPartSchema,
	ImageContentItemSchema,
	FileContentItemSchema
]);
const MessageSchema = z.object({
	role: z.enum([
		"system",
		"user",
		"assistant",
		"function",
		"tool"
	]),
	content: z.union([z.string(), z.array(ContentItemSchema)]),
	name: z.string().optional()
});
const ChatCompletionRequestSchema = z.object({
	model: z.string(),
	messages: z.array(MessageSchema),
	temperature: z.number().optional(),
	top_p: z.number().optional(),
	n: z.number().optional(),
	stream: z.boolean().optional(),
	max_tokens: z.number().optional(),
	presence_penalty: z.number().optional(),
	frequency_penalty: z.number().optional(),
	logit_bias: z.record(z.string(), z.number()).optional(),
	user: z.string().optional(),
	tools: z.record(z.string(), z.unknown()).optional(),
	runConfig: z.record(z.string(), z.unknown()).optional()
});

//#endregion
export { ChatCompletionRequestSchema, ContentItemSchema, FileContentItemSchema, ImageContentItemSchema, ImageDetailEnum, ImageDetailSchema, ImageUrlSchema, InlineDocumentDataSchema, MessageIdSchema, MessageSchema, PdfDataOrUrlSchema, VercelAudioVideoPartSchema, VercelContentPartSchema, VercelFilePartSchema, VercelImagePartSchema, VercelMessagePartSchema, VercelMessageSchema, VercelStepStartPartSchema, VercelTextPartSchema, VercelToolApprovalPartSchema };