import { NextRequest, NextResponse } from "next/server";
import { z } from "zod";
import { requireSessionOrApiKey } from "@/lib/api-auth";
import { applyRateLimit } from "@/lib/rate-limit";
import { withAiQuota, resolveAiConfigOrError } from "@/lib/ai/ai-error";
import { generateRecipe } from "@/lib/ai/features/generate-recipe";
import { getUserPrivateBio } from "@/lib/ai/user-bio";
import { withUserKey } from "@/lib/ai/resolve-user-key";
import { db, recipes, recipeIngredients, recipeSteps } from "@epicure/db";
import { parseQuantity } from "@/lib/parse-quantity";
import { checkTierLimitInTransaction, TierLimitError } from "@/lib/tiers";

const Schema = z.object({
  title: z.string().min(1).max(200),
  provider: z.enum(["openai", "anthropic", "openrouter", "ollama"]).optional(),
  model: z.string().optional(),
});

const LANG: Record<string, string> = { en: "English", fr: "French" };

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

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

  const limited = await applyRateLimit(`rl:ai:${session!.user.id}`, 10, 60);
  if (limited) return limited;

  const privateBio = await getUserPrivateBio(session!.user.id);
  const locale = (session!.user as { locale?: string }).locale ?? "en";

  const configResult = await resolveAiConfigOrError(() =>
    withUserKey(session!.user.id, { provider: parsed.data.provider, model: parsed.data.model })
  );
  if (!configResult.ok) return configResult.response;
  const aiConfig = configResult.data;

  const result = await withAiQuota(session!.user.id, session!.user.tier as "free" | "pro" | "family", () =>
    generateRecipe(parsed.data.title, {
      ...aiConfig,
      userContext: privateBio ?? undefined,
      language: LANG[locale] ?? "English",
    }), { skipQuota: aiConfig.isByok }
  );
  if (!result.ok) return result.response;
  const recipe = result.data;

  const recipeId = crypto.randomUUID();

  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: recipeId,
        authorId: session!.user.id,
        title: recipe.title,
        description: recipe.description ?? null,
        baseServings: recipe.baseServings,
        recipeType: recipe.recipeType,
        prepMins: recipe.prepMins ?? null,
        cookMins: recipe.cookMins ?? null,
        difficulty: recipe.difficulty ?? null,
        visibility: "private",
        aiGenerated: true,
        language: locale,
        dietaryTags: recipe.dietaryTags ?? {},
        tags: [],
      });

      if (recipe.ingredients?.length) {
        await tx.insert(recipeIngredients).values(
          recipe.ingredients.map((ing, i) => ({
            id: crypto.randomUUID(),
            recipeId,
            rawName: ing.rawName,
            quantity: parseQuantity(ing.quantity) ?? null,
            unit: ing.unit ?? null,
            note: ing.note ?? null,
            order: i,
          }))
        );
      }

      if (recipe.steps?.length) {
        await tx.insert(recipeSteps).values(
          recipe.steps.map((step, i) => ({
            id: crypto.randomUUID(),
            recipeId,
            instruction: step.instruction,
            timerSeconds: step.timerSeconds ?? null,
            order: i,
          }))
        );
      }
    });
  } catch (err) {
    if (err instanceof TierLimitError) {
      return NextResponse.json({ error: "Recipe limit reached for your tier" }, { status: 403 });
    }
    throw err;
  }

  return NextResponse.json({ id: recipeId });
}
