import { NextRequest, NextResponse } from "next/server";
import { db, recipes, recipeIngredients, recipeSteps, recipeSnapshots } from "@epicure/db";
import { eq, and, max, desc } from "@epicure/db";
import { requireSessionOrApiKey } from "@/lib/api-auth";
import { requireFeatureEnabledResponse } from "@/lib/feature-flags";

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

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

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

  const { id, versionId } = await params;

  // Verify ownership
  const recipe = await db.query.recipes.findFirst({
    where: and(eq(recipes.id, id), eq(recipes.authorId, session!.user.id)),
  });
  if (!recipe) return NextResponse.json({ error: "Not found" }, { status: 404 });

  const snapshot = await db.query.recipeSnapshots.findFirst({
    where: and(
      eq(recipeSnapshots.id, versionId),
      eq(recipeSnapshots.recipeId, id),
      eq(recipeSnapshots.authorId, session!.user.id)
    ),
  });
  if (!snapshot) return NextResponse.json({ error: "Not found" }, { status: 404 });

  return NextResponse.json(snapshot);
}

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

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

  const { id, versionId } = await params;

  const body = await req.json() as { action?: string };
  if (body.action !== "restore") {
    return NextResponse.json({ error: "Invalid action" }, { status: 400 });
  }

  // Verify ownership and get current recipe with relations
  const currentRecipe = 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) }, steps: { orderBy: (t, { asc }) => asc(t.order) } },
  });
  if (!currentRecipe) return NextResponse.json({ error: "Not found" }, { status: 404 });

  // Get the snapshot to restore
  const snapshot = await db.query.recipeSnapshots.findFirst({
    where: and(
      eq(recipeSnapshots.id, versionId),
      eq(recipeSnapshots.recipeId, id),
      eq(recipeSnapshots.authorId, session!.user.id)
    ),
  });
  if (!snapshot) return NextResponse.json({ error: "Snapshot not found" }, { status: 404 });

  // Restore the recipe from the snapshot
  const data = snapshot.snapshotData as {
    title: string;
    description?: string | null;
    baseServings: number;
    difficulty?: string | null;
    prepMins?: number | null;
    cookMins?: number | null;
    dietaryTags?: Record<string, boolean>;
    ingredients: Array<{ rawName: string; quantity?: string | null; unit?: string | null; note?: string | null; order: number }>;
    steps: Array<{ instruction: string; timerSeconds?: number | null; order: number }>;
  };

  await db.transaction(async (tx) => {
    await tx.update(recipes).set({
      title: data.title,
      description: data.description ?? null,
      baseServings: data.baseServings,
      difficulty: (data.difficulty as "easy" | "medium" | "hard" | null) ?? null,
      prepMins: data.prepMins ?? null,
      cookMins: data.cookMins ?? null,
      dietaryTags: data.dietaryTags ?? {},
      updatedAt: new Date(),
    }).where(eq(recipes.id, id));

    await tx.delete(recipeIngredients).where(eq(recipeIngredients.recipeId, id));
    if (data.ingredients.length > 0) {
      await tx.insert(recipeIngredients).values(
        data.ingredients.map((ing) => ({
          id: crypto.randomUUID(),
          recipeId: id,
          rawName: ing.rawName,
          quantity: ing.quantity ?? undefined,
          unit: ing.unit ?? undefined,
          note: ing.note ?? undefined,
          order: ing.order,
        }))
      );
    }

    await tx.delete(recipeSteps).where(eq(recipeSteps.recipeId, id));
    if (data.steps.length > 0) {
      await tx.insert(recipeSteps).values(
        data.steps.map((step) => ({
          id: crypto.randomUUID(),
          recipeId: id,
          instruction: step.instruction,
          timerSeconds: step.timerSeconds ?? undefined,
          order: step.order,
        }))
      );
    }
  });

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