import { z } from "zod";
import { MAX_IMAGE_SIZE_BYTES } from "@/lib/constants";
import { normalizeAiDateString } from "@/lib/date-normalizer";

/** Validates that a base64 data URL string decodes to binary under the max size. */
const isValidImageSize = (val: string): boolean => {
	const base64Part = val.split(",")[1] ?? "";
	const binarySize = Math.ceil(base64Part.length * 0.75);
	return binarySize <= MAX_IMAGE_SIZE_BYTES;
};

/** Single image data-URL validator (reused inside the array schema). */
const imageDataUrl = z
	.string()
	.regex(
		/^data:image\/(png|jpeg|webp);base64,/,
		"Must be a valid image data URL (PNG, JPEG, or WebP)",
	)
	.refine(isValidImageSize, {
		message: "Image must be less than 10MB",
	});

export const AiEventRequestSchema = z
	.object({
		prompt: z.string().trim().max(2000).optional(),
		/** Array of base64-encoded image data URLs (PNG, JPEG, WebP). */
		images: z.array(imageDataUrl).optional(),
	})
	.refine(
		(data) =>
			(data.prompt && data.prompt.trim().length > 0) ||
			(data.images && data.images.length > 0),
		{ message: "Either a prompt or at least one image is required" },
	);

export type AiEventRequest = z.infer<typeof AiEventRequestSchema>;

const aiDatetime = z.preprocess(
	(val) => (typeof val === "string" ? normalizeAiDateString(val) : val),
	z.string().datetime({ offset: true }),
);

export const AiEventResponseItemSchema = z.object({
	id: z.string().optional(),
	title: z.string().min(1),
	description: z.string().optional(),
	location: z.string().optional(),
	url: z.string().optional(),
	start: aiDatetime,
	end: aiDatetime.optional(),
	allDay: z.boolean().optional(),
	recurrenceRule: z.string().optional(),
});

export const AiEventResponseSchema = z.array(AiEventResponseItemSchema);

export type AiEventResponseItem = z.infer<typeof AiEventResponseItemSchema>;

export type CalendarEvent = AiEventResponseItem & {
	id: string;
	createdAt?: string;
	lastModified?: string;
};
