import { z } from "zod"; import { WEEKDAYS } from "@/lib/types"; import type { Weekday } from "@/lib/types"; const weekdaySchema = z.enum([ 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday', ]); export const mediaFilterSchema = z.object({ content_type: z.enum(["movie", "episode", "short"]).nullable().optional(), genres: z.array(z.string()), decade: z .number() .int() .min(1900, "Decade must be ≥ 1900") .max(2099, "Decade must be ≤ 2090") .nullable() .optional(), tags: z.array(z.string()), min_duration_secs: z.number().min(0, "Must be ≥ 0").nullable().optional(), max_duration_secs: z.number().min(0, "Must be ≥ 0").nullable().optional(), collections: z.array(z.string()), series_names: z.array(z.string()), search_term: z.string().nullable().optional(), }); export const accessModeSchema = z.enum([ "public", "password_protected", "account_required", "owner_only", ]); export const blockSchema = z.object({ id: z.string(), name: z.string().min(1, "Block name is required"), start_time: z.string(), duration_mins: z.number().int().min(1, "Must be at least 1 minute"), content: z.discriminatedUnion("type", [ z.object({ type: z.literal("algorithmic"), filter: mediaFilterSchema, strategy: z.enum(["best_fit", "sequential", "random"]), provider_id: z.string().optional(), }), z.object({ type: z.literal("manual"), items: z.array(z.string()), provider_id: z.string().optional(), }), ]), loop_on_finish: z.boolean().optional(), ignore_recycle_policy: z.boolean().optional(), access_mode: accessModeSchema.optional(), access_password: z.string().optional(), }); export const channelFormSchema = z.object({ name: z.string().min(1, "Name is required"), timezone: z.string().min(1, "Timezone is required"), description: z.string().optional(), day_blocks: z.record(weekdaySchema, z.array(blockSchema)) .default(() => Object.fromEntries(WEEKDAYS.map(d => [d, []])) as unknown as Record[]> ), recycle_policy: z.object({ cooldown_days: z.number().int().min(0).nullable().optional(), cooldown_generations: z.number().int().min(0).nullable().optional(), min_available_ratio: z .number() .min(0, "Must be ≥ 0") .max(1, "Must be ≤ 1"), }), auto_schedule: z.boolean(), access_mode: accessModeSchema.optional(), access_password: z.string().optional(), }); export type FieldErrors = Record; export function extractErrors(err: z.ZodError): FieldErrors { const map: FieldErrors = {}; for (const issue of err.issues) { const key = issue.path.join("."); if (!map[key]) map[key] = issue.message; } return map; }