import type { Metadata } from "next";
import { headers } from "next/headers";
import Link from "next/link";
import { ChevronLeft, ChevronRight, ShoppingCart, Printer, CalendarDays } from "lucide-react";
import { auth } from "@/lib/auth/server";
import { db, mealPlans, mealPlanMembers, recipes, userNutritionGoals, eq, and, desc } from "@epicure/db";
import { buttonVariants } from "@/components/ui/button";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
import { MealPlanner } from "@/components/meal-plan/meal-planner";
import { ShareMealPlanButton } from "@/components/meal-plan/share-meal-plan-button";
import { NewShoppingListButton } from "@/components/meal-plan/new-shopping-list-button";
import { WeeklyNutritionBar } from "@/components/nutrition/weekly-nutrition-bar";
import { cn } from "@/lib/utils";
import { ExportMarkdownButton } from "@/components/shared/export-markdown-button";
import { getFeatureFlagMatrix, isFeatureAvailableAnyTier, type Tier } from "@/lib/feature-flags";
import { mealPlanToMarkdown } from "@/lib/markdown/meal-plan";
import { getMessages, formatMessage } from "@/lib/i18n/server";

export const metadata: Metadata = {};

function getMonday(dateStr?: string): Date {
  // new Date("YYYY-MM-DD") parses as UTC midnight, but getDay() below reads
  // local time — in negative UTC-offset zones that's still "yesterday",
  // shifting the resolved Monday back by a full week. Parse the y/m/d parts
  // directly into local time instead.
  const d = dateStr
    ? (() => {
        const [y, m, day] = dateStr.split("-").map(Number);
        return new Date(y!, m! - 1, day!);
      })()
    : new Date();
  const dow = d.getDay();
  const diff = (dow === 0 ? -6 : 1 - dow);
  d.setDate(d.getDate() + diff);
  d.setHours(0, 0, 0, 0);
  return d;
}

function toDateStr(d: Date): string {
  // Read local y/m/d, not toISOString() (which converts to UTC and can
  // shift the date by a day depending on the server's timezone offset).
  const y = d.getFullYear();
  const m = String(d.getMonth() + 1).padStart(2, "0");
  const day = String(d.getDate()).padStart(2, "0");
  return `${y}-${m}-${day}`;
}

function addWeeks(d: Date, n: number): Date {
  const copy = new Date(d);
  copy.setDate(copy.getDate() + n * 7);
  return copy;
}

export default async function MealPlanPage({
  searchParams,
}: {
  searchParams: Promise<{ week?: string }>;
}) {
  const { week } = await searchParams;
  const session = await auth.api.getSession({ headers: await headers() });
  if (!session) return null;
  const msgs = getMessages((session.user as { locale?: string }).locale);
  const viewerTier = (session.user as { tier?: string }).tier as Tier | undefined ?? "free";
  const featureFlags = await getFeatureFlagMatrix();
  const markdownExportLocked = !featureFlags.markdown_export[viewerTier];
  const markdownExportAvailable = isFeatureAvailableAnyTier(featureFlags, "markdown_export");
  const weeklyNutritionLocked = !featureFlags.weekly_nutrition[viewerTier];
  const weeklyNutritionAvailable = isFeatureAvailableAnyTier(featureFlags, "weekly_nutrition");

  const monday = getMonday(week);
  const weekStart = toDateStr(monday);
  const prevWeek = toDateStr(addWeeks(monday, -1));
  const nextWeek = toDateStr(addWeeks(monday, 1));

  const sunday = addWeeks(monday, 1);
  sunday.setDate(sunday.getDate() - 1);

  const [plan, userRecipes, sharedMemberships, nutritionGoals] = await Promise.all([
    db.query.mealPlans.findFirst({
      where: and(eq(mealPlans.userId, session.user.id), eq(mealPlans.weekStart, weekStart)),
      with: {
        entries: {
          with: { recipe: { with: { photos: true } }, batchDish: true },
        },
      },
    }),
    db.query.recipes.findMany({
      where: eq(recipes.authorId, session.user.id),
      orderBy: desc(recipes.updatedAt),
      columns: { id: true, title: true, isBatchCook: true },
      with: { batchDishes: { columns: { id: true, name: true }, orderBy: (t, { asc }) => asc(t.order) } },
    }),
    db.query.mealPlanMembers.findMany({
      where: eq(mealPlanMembers.userId, session.user.id),
      with: { mealPlan: { with: { user: true } } },
    }),
    db.query.userNutritionGoals.findFirst({
      where: eq(userNutritionGoals.userId, session.user.id),
    }),
  ]);

  const hasNutritionGoals = !!(
    nutritionGoals &&
    (nutritionGoals.caloriesKcal || nutritionGoals.proteinG || nutritionGoals.carbsG || nutritionGoals.fatG)
  );

  const entries = (plan?.entries ?? []).map((e) => ({
    id: e.id,
    day: e.day,
    mealType: e.mealType,
    servings: e.servings,
    note: e.note,
    recipe: e.recipe ? { id: e.recipe.id, title: e.recipe.title } : null,
    batchDish: e.batchDish ? { id: e.batchDish.id, name: e.batchDish.name } : null,
  }));

  const label = `${monday.toLocaleDateString("en-US", { month: "short", day: "numeric" })} – ${sunday.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" })}`;

  return (
    <div className="space-y-6">
      <TooltipProvider>
      <div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
        <div>
          <h1 className="text-3xl font-bold tracking-tight">{msgs.mealPlan.title}</h1>
          <div className="flex items-center gap-1 mt-1">
            <Tooltip>
              <TooltipTrigger render={
                <Link href={`/meal-plan?week=${prevWeek}`} className={cn(buttonVariants({ variant: "ghost", size: "icon" }), "h-7 w-7")} aria-label={msgs.mealPlan.previousWeek}>
                  <ChevronLeft className="h-4 w-4" />
                </Link>
              } />
              <TooltipContent>{msgs.mealPlan.previousWeek}</TooltipContent>
            </Tooltip>
            <p className="text-muted-foreground">{label}</p>
            <Tooltip>
              <TooltipTrigger render={
                <Link href={`/meal-plan?week=${nextWeek}`} className={cn(buttonVariants({ variant: "ghost", size: "icon" }), "h-7 w-7")} aria-label={msgs.mealPlan.nextWeek}>
                  <ChevronRight className="h-4 w-4" />
                </Link>
              } />
              <TooltipContent>{msgs.mealPlan.nextWeek}</TooltipContent>
            </Tooltip>
          </div>
        </div>
        <div className="flex flex-wrap items-center gap-2">
          <ShareMealPlanButton weekStart={weekStart} mealPlanId={plan?.id} initialIsPublic={plan?.isPublic ?? false} />
          <NewShoppingListButton
            defaultWeekStart={weekStart}
            defaultName={formatMessage(msgs.mealPlan.shoppingListWeekName, { week: label })}
          />
          <Tooltip>
            <TooltipTrigger render={
              <Link href="/shopping-lists" className={cn(buttonVariants({ variant: "ghost", size: "icon" }))} aria-label={msgs.mealPlan.shoppingLists}>
                <ShoppingCart className="h-4 w-4" />
              </Link>
            } />
            <TooltipContent>{msgs.mealPlan.shoppingLists}</TooltipContent>
          </Tooltip>
          <Tooltip>
            <TooltipTrigger render={
              <Link href={`/print/meal-plan?week=${weekStart}`} target="_blank" className={cn(buttonVariants({ variant: "ghost", size: "icon" }))} aria-label={msgs.common.print}>
                <Printer className="h-4 w-4" />
              </Link>
            } />
            <TooltipContent>{msgs.common.print}</TooltipContent>
          </Tooltip>
          {markdownExportAvailable && (
            <ExportMarkdownButton
              markdown={mealPlanToMarkdown({ label, entries })}
              filename={`meal-plan-${weekStart}`}
              locked={markdownExportLocked}
            />
          )}
          <Tooltip>
            <TooltipTrigger render={
              <a href={`/api/v1/meal-plans/${weekStart}/export/ics`} className={cn(buttonVariants({ variant: "ghost", size: "icon" }))} aria-label={msgs.mealPlan.exportCalendar}>
                <CalendarDays className="h-4 w-4" />
              </a>
            } />
            <TooltipContent>{msgs.mealPlan.exportCalendar}</TooltipContent>
          </Tooltip>
        </div>
      </div>
      </TooltipProvider>

      {weeklyNutritionAvailable && <WeeklyNutritionBar weekStart={weekStart} locked={weeklyNutritionLocked} />}
      <MealPlanner weekStart={weekStart} initialEntries={entries} userRecipes={userRecipes} hasNutritionGoals={hasNutritionGoals} />

      {sharedMemberships.length > 0 && (
        <div className="space-y-3">
          <h2 className="text-sm font-semibold text-muted-foreground">{msgs.mealPlan.sharedWithYou}</h2>
          <div className="space-y-2 max-w-lg">
            {sharedMemberships.map((membership) => (
              <Link
                key={membership.id}
                href={`/meal-plan/shared/${membership.mealPlan.id}`}
                className="flex items-center justify-between rounded-xl border p-4 hover:shadow-sm transition-shadow"
              >
                <div>
                  <p className="font-medium">{formatMessage(msgs.mealPlan.sharedPlanOf, { name: membership.mealPlan.user?.name ?? "?" })}</p>
                  <p className="text-sm text-muted-foreground">
                    {formatMessage(msgs.mealPlan.weekOf, { date: membership.mealPlan.weekStart })} · {msgs.shareDialog[membership.role]}
                  </p>
                </div>
              </Link>
            ))}
          </div>
        </div>
      )}
    </div>
  );
}
