import { NextRequest, NextResponse } from "next/server";
import { db, recipes } from "@epicure/db";
import { eq, and, or, ne } from "@epicure/db";
import { requireSessionOrApiKey } from "@/lib/api-auth";
import { applyRateLimit } from "@/lib/rate-limit";
import { withAiQuota } from "@/lib/ai/ai-error";
import { estimateNutrition } from "@/lib/ai/features/estimate-nutrition";
import { requireFeatureEnabledResponse } from "@/lib/feature-flags";

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

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

  const recipe = await db.query.recipes.findFirst({
    where: and(
      eq(recipes.id, id),
      or(
        eq(recipes.authorId, session!.user.id),
        ne(recipes.visibility, "private")
      )
    ),
  });

  if (!recipe) return NextResponse.json({ error: "Not found" }, { status: 404 });

  return NextResponse.json({ nutrition: recipe.nutritionData ?? null, manual: recipe.nutritionManual });
}

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

  const featureDenied = await requireFeatureEnabledResponse(session!.user.id, "nutrition_estimation");
  if (featureDenied) return featureDenied;

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

  // Only the recipe author may trigger a (paid) nutrition estimate
  const recipe = await db.query.recipes.findFirst({
    where: and(eq(recipes.id, id), eq(recipes.authorId, session!.user.id)),
    with: {
      ingredients: { orderBy: (t, { asc }) => asc(t.order) },
    },
  });

  if (!recipe) return NextResponse.json({ error: "Not found" }, { status: 404 });

  const result = await withAiQuota(session!.user.id, session!.user.tier as "free" | "pro" | "family", () =>
    estimateNutrition({
      title: recipe.title,
      baseServings: recipe.baseServings,
      ingredients: recipe.ingredients.map((i) => ({
        rawName: i.rawName,
        quantity: i.quantity,
        unit: i.unit,
      })),
    })
  );
  if (!result.ok) return result.response;

  await db.update(recipes).set({ nutritionData: result.data, nutritionManual: false }).where(and(eq(recipes.id, id), eq(recipes.authorId, session!.user.id)));

  return NextResponse.json({ nutrition: result.data });
}
