import { NextRequest, NextResponse } from "next/server";
import { db, mealPlans, mealPlanEntries, userNutritionGoals, eq, and } from "@epicure/db";
import { requireSessionOrApiKey } from "@/lib/api-auth";
import { requireFeatureEnabledResponse } from "@/lib/feature-flags";

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

type Weekday = "mon" | "tue" | "wed" | "thu" | "fri" | "sat" | "sun";

type Totals = { calories: number; protein: number; carbs: number; fat: number };

function emptyTotals(): Totals {
  return { calories: 0, protein: 0, carbs: 0, fat: 0 };
}

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

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

  const { weekStart } = await params;
  const userId = session!.user.id;

  const plan = await db.query.mealPlans.findFirst({
    where: and(eq(mealPlans.userId, userId), eq(mealPlans.weekStart, weekStart)),
  });

  const weekTotals = emptyTotals();
  const byDay: Record<Weekday, Totals> = {
    mon: emptyTotals(), tue: emptyTotals(), wed: emptyTotals(), thu: emptyTotals(),
    fri: emptyTotals(), sat: emptyTotals(), sun: emptyTotals(),
  };
  let unknownCount = 0;
  let plannedDays = 0;

  if (plan) {
    // batchDishId entries always carry their parent recipeId too (enforced at
    // entry-creation time), so joining on `recipe` already covers batch
    // dishes — there's no separate per-dish nutrition data to look up.
    const entries = await db.query.mealPlanEntries.findMany({
      where: eq(mealPlanEntries.mealPlanId, plan.id),
      with: {
        recipe: {
          columns: { id: true, baseServings: true, nutritionData: true },
        },
      },
    });

    const daysWithEntries = new Set<string>();
    for (const entry of entries) {
      daysWithEntries.add(entry.day);
      const recipe = entry.recipe;
      if (!recipe || !recipe.nutritionData?.perServing) {
        unknownCount++;
        continue;
      }

      const { calories, proteinG, carbsG, fatG } = recipe.nutritionData.perServing;
      const servings = entry.servings ?? recipe.baseServings;
      const day = byDay[entry.day as Weekday];

      const cals = Math.round(calories * servings);
      const protein = Math.round(proteinG * servings);
      const carbs = Math.round(carbsG * servings);
      const fat = Math.round(fatG * servings);

      weekTotals.calories += cals;
      weekTotals.protein += protein;
      weekTotals.carbs += carbs;
      weekTotals.fat += fat;
      day.calories += cals;
      day.protein += protein;
      day.carbs += carbs;
      day.fat += fat;
    }
    plannedDays = daysWithEntries.size;
  }

  const goals = await db.query.userNutritionGoals.findFirst({
    where: eq(userNutritionGoals.userId, userId),
  });

  const goalsData = goals
    ? { caloriesKcal: goals.caloriesKcal, proteinG: goals.proteinG, carbsG: goals.carbsG, fatG: goals.fatG }
    : null;

  // Goals are daily targets (see the nutrition diary, which compares a single
  // day's totals against them directly) — a week's raw total is ~7x a daily
  // goal, so coverage must compare against the daily AVERAGE across days that
  // actually have planned meals, not the week's total.
  const divisor = plannedDays || 1;
  const dailyAverage: Totals = {
    calories: Math.round(weekTotals.calories / divisor),
    protein: Math.round(weekTotals.protein / divisor),
    carbs: Math.round(weekTotals.carbs / divisor),
    fat: Math.round(weekTotals.fat / divisor),
  };

  const coverage = {
    calories: goalsData?.caloriesKcal ? Math.round((dailyAverage.calories / goalsData.caloriesKcal) * 100) : 0,
    protein: goalsData?.proteinG ? Math.round((dailyAverage.protein / goalsData.proteinG) * 100) : 0,
    carbs: goalsData?.carbsG ? Math.round((dailyAverage.carbs / goalsData.carbsG) * 100) : 0,
    fat: goalsData?.fatG ? Math.round((dailyAverage.fat / goalsData.fatG) * 100) : 0,
  };

  return NextResponse.json({
    totals: weekTotals,
    dailyAverage,
    byDay,
    plannedDays,
    unknownCount,
    goals: goalsData,
    coverage,
  });
}
