'use server' import { z } from 'zod' import { db } from '@/lib/db' import { courses, tees, holes } from '@/lib/db/schema' import { auth } from '@/lib/auth' import { headers } from 'next/headers' import { revalidatePath } from 'next/cache' const TeeInput = z.object({ name: z.string().min(1, 'Tee name required'), color: z.string().regex(/^#[0-9a-fA-F]{6}$/), courseRating: z.coerce.number().min(50).max(80), slopeRating: z.coerce.number().int().min(55).max(155), }) const HoleInput = z.object({ holeNumber: z.number().int().min(1).max(18), par: z.number().int().min(3).max(5), strokeIndex: z.number().int().min(1).max(18), }) export const CreateCourseSchema = z.object({ name: z.string().min(1, 'Course name required').max(100), par: z.number().int().min(27).max(90), tees: z.array(TeeInput).min(1, 'At least one tee required'), holes: z.array(HoleInput).min(9), }) export type CreateCourseInput = z.infer export async function createCourse(data: CreateCourseInput) { const parsed = CreateCourseSchema.safeParse(data) if (!parsed.success) return { error: parsed.error.issues[0]?.message ?? 'Invalid data' } const session = await auth.api.getSession({ headers: await headers() }) if (!session) return { error: 'Not authenticated' } // Validate par sum equals declared course par const parSum = parsed.data.holes.reduce((s, h) => s + h.par, 0) if (parSum !== parsed.data.par) { return { error: `Sum of hole pars (${parSum}) does not equal course par (${parsed.data.par})` } } const [course] = await db .insert(courses) .values({ name: parsed.data.name, par: parsed.data.par, createdBy: session.user.id }) .returning({ id: courses.id }) await db.insert(tees).values( parsed.data.tees.map((t) => ({ courseId: course.id, name: t.name, color: t.color, courseRating: String(t.courseRating), slopeRating: t.slopeRating, })), ) await db.insert(holes).values( parsed.data.holes.map((h) => ({ courseId: course.id, holeNumber: h.holeNumber, par: h.par, strokeIndex: h.strokeIndex, })), ) revalidatePath('/rounds/new') return { courseId: course.id } }