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

const BulkDeleteSchema = z.object({
  ids: z.array(z.string()).min(1).max(100),
});

const BulkUpdateSchema = z.object({
  ids: z.array(z.string()).min(1).max(100),
  visibility: z.enum(["private", "unlisted", "public", "followers"]).optional(),
  addTags: z.array(z.string().min(1).max(40)).max(20).optional(),
  removeTags: z.array(z.string().min(1).max(40)).max(20).optional(),
});

export async function DELETE(req: NextRequest) {
  const { session, response } = await requireSessionOrApiKey(req);
  if (response) return response;

  const body = BulkDeleteSchema.safeParse(await req.json());
  if (!body.success) return NextResponse.json({ error: "Invalid request" }, { status: 400 });

  await db
    .delete(recipes)
    .where(and(inArray(recipes.id, body.data.ids), eq(recipes.authorId, session!.user.id)));

  return NextResponse.json({ ok: true });
}

export async function PATCH(req: NextRequest) {
  const { session, response } = await requireSessionOrApiKey(req);
  if (response) return response;

  const body = BulkUpdateSchema.safeParse(await req.json());
  if (!body.success) return NextResponse.json({ error: "Invalid request" }, { status: 400 });

  const { ids, visibility, addTags, removeTags } = body.data;
  if (!visibility && !addTags?.length && !removeTags?.length) {
    return NextResponse.json({ error: "Nothing to update" }, { status: 400 });
  }

  if (visibility) {
    await db
      .update(recipes)
      .set({ visibility, updatedAt: new Date() })
      .where(and(inArray(recipes.id, ids), eq(recipes.authorId, session!.user.id)));
  }

  if (addTags?.length || removeTags?.length) {
    const owned = await db.query.recipes.findMany({
      where: and(inArray(recipes.id, ids), eq(recipes.authorId, session!.user.id)),
      columns: { id: true, tags: true },
    });

    await Promise.all(
      owned.map((r) => {
        let nextTags = r.tags;
        if (addTags?.length) nextTags = [...new Set([...nextTags, ...addTags])];
        if (removeTags?.length) nextTags = nextTags.filter((tag) => !removeTags.includes(tag));
        return db.update(recipes).set({ tags: nextTags, updatedAt: new Date() }).where(eq(recipes.id, r.id));
      })
    );
  }

  return NextResponse.json({ ok: true });
}
