import { NextResponse } from "next/server";
import {
  db,
  eq,
  or,
  users,
  recipes,
  recipeIngredients,
  recipeSteps,
  recipePhotos,
  recipeNotes,
  ratings,
  favorites,
  comments,
  collections,
  collectionRecipes,
  collectionFavorites,
  cookingHistory,
  notifications,
  userFollows,
  mealPlans,
  mealPlanEntries,
  pantryItems,
  shoppingLists,
  shoppingListItems,
  webhooks,
  apiKeys,
  pushSubscriptions,
  userNutritionGoals,
  userAllergens,
  userModelPrefs,
  userUsage,
  messages,
  conversations,
} from "@epicure/db";
import { requireSession } from "@/lib/api-auth";
import { applyRateLimit } from "@/lib/rate-limit";

export async function GET() {
  const { session, response } = await requireSession();
  if (response) return response;

  const userId = session!.user.id;

  const limited = await applyRateLimit(`rl:export:${userId}`, 3, 3600);
  if (limited) return limited;

  const [
    profileRows,
    userRecipes,
    userRatings,
    userComments,
    userNotes,
    userFavorites,
    following,
    followers,
    userCollections,
    userCookingHistory,
    userNotifications,
    userMealPlans,
    userPantryItems,
    userShoppingLists,
    userWebhooks,
    userApiKeys,
    userPushSubscriptions,
    userNutritionGoalsRows,
    userAllergenRows,
    userMessages,
    userModelPrefsRows,
    userUsageRows,
  ] = await Promise.all([
    db
      .select({
        id: users.id,
        email: users.email,
        name: users.name,
        username: users.username,
        bio: users.bio,
        privateBio: users.privateBio,
        avatarUrl: users.avatarUrl,
        role: users.role,
        tier: users.tier,
        unitPref: users.unitPref,
        locale: users.locale,
        createdAt: users.createdAt,
        updatedAt: users.updatedAt,
      })
      .from(users)
      .where(eq(users.id, userId))
      .limit(1),
    db.select().from(recipes).where(eq(recipes.authorId, userId)),
    db.select().from(ratings).where(eq(ratings.userId, userId)),
    db.select().from(comments).where(eq(comments.userId, userId)),
    db.select().from(recipeNotes).where(eq(recipeNotes.userId, userId)),
    db.select().from(favorites).where(eq(favorites.userId, userId)),
    db
      .select({ followingId: userFollows.followingId, createdAt: userFollows.createdAt })
      .from(userFollows)
      .where(eq(userFollows.followerId, userId)),
    db
      .select({ followerId: userFollows.followerId, createdAt: userFollows.createdAt })
      .from(userFollows)
      .where(eq(userFollows.followingId, userId)),
    db.select().from(collections).where(eq(collections.userId, userId)),
    db.select().from(cookingHistory).where(eq(cookingHistory.userId, userId)),
    db.select().from(notifications).where(eq(notifications.userId, userId)),
    db.select().from(mealPlans).where(eq(mealPlans.userId, userId)),
    db.select().from(pantryItems).where(eq(pantryItems.userId, userId)),
    db.select().from(shoppingLists).where(eq(shoppingLists.userId, userId)),
    db
      .select({
        id: webhooks.id,
        url: webhooks.url,
        events: webhooks.events,
        active: webhooks.active,
        createdAt: webhooks.createdAt,
      })
      .from(webhooks)
      .where(eq(webhooks.userId, userId)),
    db
      .select({
        id: apiKeys.id,
        name: apiKeys.name,
        lastUsedAt: apiKeys.lastUsedAt,
        createdAt: apiKeys.createdAt,
      })
      .from(apiKeys)
      .where(eq(apiKeys.userId, userId)),
    db
      .select({ id: pushSubscriptions.id, endpoint: pushSubscriptions.endpoint, createdAt: pushSubscriptions.createdAt })
      .from(pushSubscriptions)
      .where(eq(pushSubscriptions.userId, userId)),
    db.select().from(userNutritionGoals).where(eq(userNutritionGoals.userId, userId)),
    db.select().from(userAllergens).where(eq(userAllergens.userId, userId)),
    db
      .select({
        id: messages.id,
        conversationId: messages.conversationId,
        content: messages.content,
        createdAt: messages.createdAt,
      })
      .from(messages)
      .where(eq(messages.senderId, userId)),
    db.select().from(userModelPrefs).where(eq(userModelPrefs.userId, userId)),
    db.select().from(userUsage).where(eq(userUsage.userId, userId)),
  ]);

  const profile = profileRows[0] ?? null;

  // Recipe sub-data (ingredients/steps/photos) scoped to this user's own recipes.
  const recipeIds = userRecipes.map((r) => r.id);
  const [ingredientsRows, stepsRows, photosRows] = recipeIds.length
    ? await Promise.all([
        db.select().from(recipeIngredients).where(or(...recipeIds.map((id) => eq(recipeIngredients.recipeId, id)))),
        db.select().from(recipeSteps).where(or(...recipeIds.map((id) => eq(recipeSteps.recipeId, id)))),
        db.select().from(recipePhotos).where(or(...recipeIds.map((id) => eq(recipePhotos.recipeId, id)))),
      ])
    : [[], [], []];

  const mealPlanIds = userMealPlans.map((p) => p.id);
  const mealPlanEntriesRows = mealPlanIds.length
    ? await db.select().from(mealPlanEntries).where(or(...mealPlanIds.map((id) => eq(mealPlanEntries.mealPlanId, id))))
    : [];

  const shoppingListIds = userShoppingLists.map((l) => l.id);
  const shoppingListItemsRows = shoppingListIds.length
    ? await db.select().from(shoppingListItems).where(or(...shoppingListIds.map((id) => eq(shoppingListItems.listId, id))))
    : [];

  const collectionIds = userCollections.map((c) => c.id);
  const [collectionRecipesRows, collectionFavoritesRows] = collectionIds.length
    ? await Promise.all([
        db.select().from(collectionRecipes).where(or(...collectionIds.map((id) => eq(collectionRecipes.collectionId, id)))),
        db.select().from(collectionFavorites).where(eq(collectionFavorites.userId, userId)),
      ])
    : [[], await db.select().from(collectionFavorites).where(eq(collectionFavorites.userId, userId))];

  const conversationIds = [...new Set(userMessages.map((m) => m.conversationId))];
  const conversationRows = conversationIds.length
    ? await db.select().from(conversations).where(or(...conversationIds.map((id) => eq(conversations.id, id))))
    : [];

  const exportData = {
    exportedAt: new Date().toISOString(),
    profile,
    recipes: userRecipes.map((r) => ({
      ...r,
      ingredients: ingredientsRows.filter((i) => i.recipeId === r.id),
      steps: stepsRows.filter((s) => s.recipeId === r.id),
      photos: photosRows.filter((p) => p.recipeId === r.id),
    })),
    ratings: userRatings,
    comments: userComments,
    recipeNotes: userNotes,
    favorites: userFavorites,
    social: {
      following,
      followers,
    },
    collections: userCollections.map((c) => ({
      ...c,
      recipeIds: collectionRecipesRows.filter((cr) => cr.collectionId === c.id).map((cr) => cr.recipeId),
    })),
    favoriteCollections: collectionFavoritesRows,
    cookingHistory: userCookingHistory,
    notifications: userNotifications,
    mealPlans: userMealPlans.map((p) => ({
      ...p,
      entries: mealPlanEntriesRows.filter((e) => e.mealPlanId === p.id),
    })),
    pantryItems: userPantryItems,
    shoppingLists: userShoppingLists.map((l) => ({
      ...l,
      items: shoppingListItemsRows.filter((i) => i.listId === l.id),
    })),
    webhooks: userWebhooks,
    apiKeys: userApiKeys,
    pushSubscriptions: userPushSubscriptions,
    nutritionGoals: userNutritionGoalsRows,
    allergens: userAllergenRows,
    modelPreferences: userModelPrefsRows,
    usage: userUsageRows,
    messages: userMessages.map((m) => {
      const conversation = conversationRows.find((c) => c.id === m.conversationId);
      const otherUserId = conversation ? (conversation.userAId === userId ? conversation.userBId : conversation.userAId) : null;
      return { ...m, otherUserId };
    }),
  };

  const dateStr = new Date().toISOString().slice(0, 10);

  return new NextResponse(JSON.stringify(exportData, null, 2), {
    status: 200,
    headers: {
      "Content-Type": "application/json",
      "Content-Disposition": `attachment; filename="epicure-data-export-${dateStr}.json"`,
    },
  });
}
