import { NextRequest, NextResponse } from "next/server";
import { db, recipes, recipeIngredients, recipeSteps, recipeVariations } from "@epicure/db";
import { eq, and, or, inArray } from "@epicure/db";
import { requireSessionOrApiKey } from "@/lib/api-auth";
import { checkTierLimitInTransaction, TierLimitError } from "@/lib/tiers";

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

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

  const source = await db.query.recipes.findFirst({
    where: and(
      eq(recipes.id, id),
      or(eq(recipes.authorId, session!.user.id), inArray(recipes.visibility, ["public", "unlisted"]))
    ),
    with: {
      ingredients: { orderBy: (t, { asc }) => asc(t.order) },
      steps: { orderBy: (t, { asc }) => asc(t.order) },
    },
  });
  if (!source) return NextResponse.json({ error: "Not found" }, { status: 404 });

  const newId = crypto.randomUUID();
  const now = new Date();

  try {
    await db.transaction(async (tx) => {
      await checkTierLimitInTransaction(tx, session!.user.id, session!.user.tier as "free" | "pro" | "family", "recipe");
      await tx.insert(recipes).values({
        id: newId,
        authorId: session!.user.id,
        title: source.title,
        description: source.description,
        baseServings: source.baseServings,
        visibility: "private",
        difficulty: source.difficulty,
        prepMins: source.prepMins,
        cookMins: source.cookMins,
        tags: source.tags,
        dietaryTags: source.dietaryTags ?? {},
        aiGenerated: false,
        language: source.language,
        createdAt: now,
        updatedAt: now,
      });

      if (source.ingredients.length > 0) {
        await tx.insert(recipeIngredients).values(
          source.ingredients.map((ing) => ({
            id: crypto.randomUUID(),
            recipeId: newId,
            rawName: ing.rawName,
            quantity: ing.quantity,
            unit: ing.unit,
            note: ing.note,
            order: ing.order,
          }))
        );
      }

      if (source.steps.length > 0) {
        await tx.insert(recipeSteps).values(
          source.steps.map((step) => ({
            id: crypto.randomUUID(),
            recipeId: newId,
            instruction: step.instruction,
            timerSeconds: step.timerSeconds,
            order: step.order,
          }))
        );
      }

      await tx.insert(recipeVariations).values({
        id: crypto.randomUUID(),
        parentRecipeId: source.id,
        childRecipeId: newId,
        description: null,
        aiGenerated: false,
        createdAt: now,
      });
    });
  } catch (err) {
    if (err instanceof TierLimitError) {
      return NextResponse.json({ error: "Recipe limit reached for your tier" }, { status: 403 });
    }
    throw err;
  }

  return NextResponse.json({ id: newId }, { status: 201 });
}
