import { NextRequest, NextResponse } from "next/server";
import { db, recipes, recipeNotes, eq, and, or, inArray } from "@epicure/db";
import { z } from "zod";
import { requireSessionOrApiKey } from "@/lib/api-auth";

type Params = { params: Promise<{ id: string }> };

const PutSchema = z.object({
  content: z.string().max(5000),
});

async function assertRecipeAccessible(recipeId: string, userId: string) {
  const recipe = await db.query.recipes.findFirst({
    where: and(
      eq(recipes.id, recipeId),
      or(eq(recipes.authorId, userId), inArray(recipes.visibility, ["public", "unlisted"]))
    ),
    columns: { id: true },
  });
  return recipe;
}

export async function GET(req: NextRequest, { params }: Params) {
  const { session, response } = await requireSessionOrApiKey(req, { rateLimit: { limit: 60, windowSeconds: 60 } });
  if (response) return response;
  const { id } = await params;

  const recipe = await assertRecipeAccessible(id, session!.user.id);
  if (!recipe) return NextResponse.json({ error: "Not found" }, { status: 404 });

  const note = await db.query.recipeNotes.findFirst({
    where: and(eq(recipeNotes.recipeId, id), eq(recipeNotes.userId, session!.user.id)),
    columns: { content: true, updatedAt: true },
  });

  return NextResponse.json({ note: note ?? null });
}

export async function PUT(req: NextRequest, { params }: Params) {
  const { session, response } = await requireSessionOrApiKey(req, { rateLimit: { limit: 60, windowSeconds: 60 } });
  if (response) return response;
  const { id } = await params;

  const recipe = await assertRecipeAccessible(id, session!.user.id);
  if (!recipe) return NextResponse.json({ error: "Not found" }, { status: 404 });

  const parsed = PutSchema.safeParse(await req.json());
  if (!parsed.success) {
    return NextResponse.json({ error: "Validation error", issues: parsed.error.issues }, { status: 400 });
  }

  const content = parsed.data.content.trim();
  const userId = session!.user.id;

  if (content.length === 0) {
    await db
      .delete(recipeNotes)
      .where(and(eq(recipeNotes.recipeId, id), eq(recipeNotes.userId, userId)));
    return NextResponse.json({ note: null });
  }

  await db
    .insert(recipeNotes)
    .values({ id: crypto.randomUUID(), recipeId: id, userId, content, updatedAt: new Date() })
    .onConflictDoUpdate({
      target: [recipeNotes.recipeId, recipeNotes.userId],
      set: { content, updatedAt: new Date() },
    });

  const note = await db.query.recipeNotes.findFirst({
    where: and(eq(recipeNotes.recipeId, id), eq(recipeNotes.userId, userId)),
    columns: { content: true, updatedAt: true },
  });

  return NextResponse.json({ note });
}
