import type { Metadata } from "next";
import Image from "next/image";
import { notFound } from "next/navigation";
import { headers } from "next/headers";
import Link from "next/link";
import { Clock, Users, Globe, Lock, Link2, Pencil, ChefHat, ExternalLink, Play, UserCheck } from "lucide-react";
import { VariationsButton } from "@/components/recipe/variations-button";
import { TranslateButton } from "@/components/recipe/translate-button";
import { AddToShoppingListButton } from "@/components/recipe/add-to-shopping-list-button";
import { MealPairingButton } from "@/components/recipe/meal-pairing-button";
import { DrinkPairingButton } from "@/components/recipe/drink-pairing-button";
import { AdaptRecipeButton } from "@/components/recipe/adapt-recipe-button";
import { PrintButton } from "@/components/recipe/print-button";
import { ShareRecipeButton } from "@/components/recipe/share-recipe-button";
import { SaveOfflineButton } from "@/components/recipe/save-offline-button";
import { VersionHistoryButton } from "@/components/recipe/version-history-button";
import { ForkedByPopover } from "@/components/recipe/forked-by-popover";
import { DeleteRecipeButton } from "@/components/recipe/delete-recipe-button";
import { ForkRecipeButton } from "@/components/recipe/fork-recipe-button";
import { NutritionPanel } from "@/components/recipe/nutrition-panel";
import { GenerateContentButton } from "@/components/recipe/generate-content-button";
import { auth } from "@/lib/auth/server";
import { db, recipes, ratings, favorites, recipeVariations, recipeNotes, cookingHistory, avg } from "@epicure/db";
import { and, eq, count, desc } from "@epicure/db";
import { visibleToViewer } from "@/lib/visibility";
import { Badge } from "@/components/ui/badge";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { buttonVariants } from "@/components/ui/button";
import { Separator } from "@/components/ui/separator";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
import { ServingScaler } from "@/components/recipe/serving-scaler";
import { FavoriteButton } from "@/components/social/favorite-button";
import { RatingStars } from "@/components/social/rating-stars";
import { CookedItReview } from "@/components/social/cooked-it-review";
import { MarkCookedSection } from "@/components/recipe/mark-cooked-section";
import { RecipeNotes } from "@/components/recipe/recipe-notes";
import { CommentsSection } from "@/components/social/comments-section";
import { getPublicUrl } from "@/lib/storage";
import { cn, stripMarkdown } from "@/lib/utils";
import { RecipeChatPanel } from "@/components/recipe/recipe-chat-panel";
import { getFeaturePrefs } from "@/lib/feature-prefs";
import { BatchCookSteps } from "@/components/recipe/batch-cook-steps";
import { BatchCookDishes } from "@/components/recipe/batch-cook-dishes";
import { KeepScreenAwake } from "@/components/recipe/keep-screen-awake";
import { ExportMarkdownButton } from "@/components/shared/export-markdown-button";
import { recipeToMarkdown } from "@/lib/markdown/recipe";
import { getMessages, formatMessage } from "@/lib/i18n/server";
import { getFeatureFlagMatrix, isFeatureAvailableAnyTier, type Tier } from "@/lib/feature-flags";

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

export async function generateMetadata({ params }: Params): Promise<Metadata> {
  const { id } = await params;
  const session = await auth.api.getSession({ headers: await headers() });
  if (!session) return { title: "Recipe" };
  const recipe = await db.query.recipes.findFirst({
    where: and(
      eq(recipes.id, id),
      visibleToViewer(session.user.id)
    ),
  });
  return { title: recipe?.title ?? "Recipe" };
}

const VISIBILITY_ICON = { private: Lock, unlisted: Link2, public: Globe, followers: UserCheck };
const DIFFICULTY_COLOR = { easy: "default", medium: "secondary", hard: "destructive" } as const;

export default async function RecipePage({ params }: Params) {
  const { id } = await params;
  const session = await auth.api.getSession({ headers: await headers() });
  if (!session) return null;

  const m = getMessages((session.user as { locale?: string }).locale);
  const VISIBILITY_LABEL = m.recipe.visibility;
  const DIETARY_LABELS = m.recipe.dietary;
  const unitPref = (session.user as { unitPref?: string }).unitPref === "imperial" ? "imperial" : "metric";

  const [recipe, ratingData, favoriteData, myRating, forkedFrom, forkedTo, myNote, dishCookLog, featureFlags, featurePrefs] = await Promise.all([
    db.query.recipes.findFirst({
      where: and(
        eq(recipes.id, id),
        visibleToViewer(session.user.id)
      ),
      with: {
        ingredients: { orderBy: (t, { asc }) => asc(t.order) },
        steps: { orderBy: (t, { asc }) => asc(t.order) },
        photos: { orderBy: (t, { asc }) => asc(t.order) },
        author: { columns: { id: true, name: true, username: true, avatarUrl: true } },
        batchDishes: { orderBy: (t, { asc }) => asc(t.order) },
      },
    }),
    db.select({ avgScore: avg(ratings.score), total: count() }).from(ratings).where(eq(ratings.recipeId, id)),
    db.query.favorites.findFirst({ where: and(eq(favorites.userId, session.user.id), eq(favorites.recipeId, id)) }),
    db.query.ratings.findFirst({ where: and(eq(ratings.recipeId, id), eq(ratings.userId, session.user.id)) }),
    db.query.recipeVariations.findFirst({
      where: eq(recipeVariations.childRecipeId, id),
      with: { parent: { columns: { id: true, title: true } } },
    }),
    db.query.recipeVariations.findMany({
      where: eq(recipeVariations.parentRecipeId, id),
      orderBy: (t, { desc }) => desc(t.createdAt),
      with: {
        child: { columns: { id: true, title: true, visibility: true, authorId: true } },
      },
    }),
    db.query.recipeNotes.findFirst({
      where: and(eq(recipeNotes.recipeId, id), eq(recipeNotes.userId, session.user.id)),
      columns: { content: true },
    }),
    db.query.cookingHistory.findMany({
      where: and(eq(cookingHistory.recipeId, id), eq(cookingHistory.userId, session.user.id)),
      orderBy: desc(cookingHistory.cookedAt),
      columns: { id: true, batchDishId: true, cookedAt: true, servings: true, notes: true },
    }),
    getFeatureFlagMatrix(),
    getFeaturePrefs(session.user.id),
  ]);

  if (!recipe) notFound();

  const viewerTier = (session.user as { tier?: string }).tier as Tier | undefined ?? "free";
  const locked = {
    variations: !featureFlags.recipe_variations[viewerTier],
    drinkPairing: !featureFlags.drink_pairing[viewerTier],
    mealPairing: !featureFlags.meal_pairing[viewerTier],
    nutritionEstimation: !featureFlags.nutrition_estimation[viewerTier],
    markdownExport: !featureFlags.markdown_export[viewerTier],
    versionHistory: !featureFlags.version_history[viewerTier],
  };
  // A feature disabled for every tier has no upgrade path, so it hides
  // outright; one enabled for at least one tier still shows (locked, with a
  // "Pro" upsell) even when the viewer's own tier lacks it.
  const available = {
    variations: isFeatureAvailableAnyTier(featureFlags, "recipe_variations"),
    drinkPairing: isFeatureAvailableAnyTier(featureFlags, "drink_pairing"),
    mealPairing: isFeatureAvailableAnyTier(featureFlags, "meal_pairing"),
    nutritionEstimation: isFeatureAvailableAnyTier(featureFlags, "nutrition_estimation"),
    markdownExport: isFeatureAvailableAnyTier(featureFlags, "markdown_export"),
    versionHistory: isFeatureAvailableAnyTier(featureFlags, "version_history"),
  };

  const isOwner = recipe.authorId === session.user.id;

  // Don't leak the existence/title of someone else's private fork —
  // only surface forks that are themselves public/unlisted, or that the
  // viewer made themselves.
  const visibleForks = forkedTo.filter(
    (f) => f.child.visibility !== "private" || f.child.authorId === session.user.id
  );

  const dishCookedAtMap = new Map<string, string>();
  for (const log of dishCookLog) {
    if (log.batchDishId && !dishCookedAtMap.has(log.batchDishId)) {
      dishCookedAtMap.set(log.batchDishId, log.cookedAt.toISOString());
    }
  }

  // Non-batch cook log — batch-cook recipes track this per-dish instead
  // (dishCookedAtMap above), logged via BatchCookDishes, not this list.
  const plainCookLog = dishCookLog
    .filter((l) => !l.batchDishId)
    .map((l) => ({ id: l.id, cookedAt: l.cookedAt.toISOString(), servings: l.servings, notes: l.notes }));

  const avgScore = ratingData[0]?.avgScore ? parseFloat(ratingData[0].avgScore) : null;
  const ratingCount = ratingData[0]?.total ?? 0;
  const isFavorited = !!favoriteData;
  const myScore = myRating?.score ?? 0;

  const cover = recipe.photos.find((p) => p.isCover) ?? recipe.photos[0];
  const totalMins = (recipe.prepMins ?? 0) + (recipe.cookMins ?? 0);
  const activeDietaryTags = Object.entries(recipe.dietaryTags ?? {})
    .filter(([, v]) => v)
    .map(([k]) => DIETARY_LABELS[k as keyof typeof DIETARY_LABELS])
    .filter(Boolean);

  const VisibilityIcon = VISIBILITY_ICON[recipe.visibility];

  return (
    <div className="max-w-4xl mx-auto space-y-8 pb-20">
      {/* pb-20 keeps the last section (private notes' Save button) clear of
          the fixed recipe-chat button, which otherwise overlaps it on short
          pages — same fix as recipe-form.tsx's floating save bar. */}
      <KeepScreenAwake />
      {/* Header */}
      <div className="space-y-4">
        <div className="flex items-center gap-3">
          <h1 className="text-3xl font-bold tracking-tight">{recipe.title}</h1>
          {recipe.isBatchCook && (
            <Badge variant="secondary" className="shrink-0">{m.recipe.batchCookBadge}</Badge>
          )}
        </div>
        {!isOwner && recipe.author.username && (
          <Link
            href={`/u/${recipe.author.username}`}
            className="inline-flex items-center gap-2 text-sm text-muted-foreground hover:text-foreground"
          >
            <Avatar className="h-6 w-6">
              {recipe.author.avatarUrl && <AvatarImage src={recipe.author.avatarUrl} alt={recipe.author.name} />}
              <AvatarFallback className="text-[10px]">{recipe.author.name.slice(0, 2).toUpperCase()}</AvatarFallback>
            </Avatar>
            {formatMessage(m.recipe.byAuthor, { name: recipe.author.name })}
          </Link>
        )}
        {forkedFrom && (
          <Link
            href={`/recipes/${forkedFrom.parent.id}`}
            className="inline-flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground"
          >
            {formatMessage(m.recipe.forkedFrom, { title: forkedFrom.parent.title })}
          </Link>
        )}
        {visibleForks.length > 0 && (
          <ForkedByPopover
            label={
              visibleForks.length === 1
                ? m.recipe.forkedByCountSingular
                : formatMessage(m.recipe.forkedByCountPlural, { count: visibleForks.length })
            }
            forks={visibleForks.map((f) => ({ id: f.child.id, title: f.child.title }))}
          />
        )}
        <TooltipProvider>
        <div className="flex items-center gap-2 overflow-x-auto pb-0.5 [scrollbar-width:none] [-ms-overflow-style:none] [&::-webkit-scrollbar]:hidden">
            {recipe.steps.length > 0 && (
              <Tooltip>
                <TooltipTrigger render={
                  <Link href={`/recipes/${id}/cook`} className={cn(buttonVariants({ variant: "ghost", size: "icon" }))}>
                    <Play className="h-4 w-4" />
                  </Link>
                } />
                <TooltipContent>{m.recipe.cookAction}</TooltipContent>
              </Tooltip>
            )}
            <FavoriteButton recipeId={id} initialFavorited={isFavorited} />
            {!recipe.isBatchCook && recipe.recipeType !== "drink" && (
              <>
                {available.mealPairing && <MealPairingButton recipeId={id} locked={locked.mealPairing} />}
                {available.drinkPairing && <DrinkPairingButton recipeId={id} locked={locked.drinkPairing} />}
              </>
            )}
            {recipe.visibility === "public" && (
              <Tooltip>
                <TooltipTrigger render={
                  <Link href={`/r/${id}`} target="_blank" className={cn(buttonVariants({ variant: "ghost", size: "icon" }))}>
                    <ExternalLink className="h-4 w-4" />
                  </Link>
                } />
                <TooltipContent>{m.recipe.viewPublicly}</TooltipContent>
              </Tooltip>
            )}
            {recipe.ingredients.length > 0 && (
              <AddToShoppingListButton
                recipeId={id}
                recipeTitle={recipe.title}
                baseServings={recipe.baseServings}
                ingredients={recipe.ingredients.map((ing) => ({
                  rawName: ing.rawName,
                  quantity: ing.quantity,
                  unit: ing.unit,
                }))}
              />
            )}
            {isOwner && (!recipe.language || recipe.language !== (session.user as { locale?: string }).locale) && (
              <TranslateButton recipeId={id} />
            )}
            {recipe.ingredients.length > 0 && (
              <AdaptRecipeButton
                recipeId={id}
                ingredients={recipe.ingredients.map((ing) => ({ rawName: ing.rawName }))}
              />
            )}
            {available.variations && (
              <VariationsButton
                recipeId={id}
                baseServings={recipe.baseServings}
                difficulty={recipe.difficulty}
                prepMins={recipe.prepMins}
                cookMins={recipe.cookMins}
                ingredients={recipe.ingredients.map((ing) => ({
                  rawName: ing.rawName,
                  quantity: ing.quantity,
                  unit: ing.unit,
                  note: ing.note,
                  order: ing.order,
                }))}
                steps={recipe.steps.map((s) => ({
                  instruction: s.instruction,
                  timerSeconds: s.timerSeconds,
                  order: s.order,
                }))}
                locked={locked.variations}
              />
            )}
            <ForkRecipeButton recipeId={id} variant={isOwner ? "duplicate" : "fork"} />
            <ShareRecipeButton recipeId={id} visibility={recipe.visibility} />
            <SaveOfflineButton recipeId={id} recipeTitle={recipe.title} />
            <PrintButton recipeId={id} />
            {available.markdownExport && (
              <ExportMarkdownButton
                markdown={recipeToMarkdown({
                  title: recipe.title,
                  description: recipe.description,
                  baseServings: recipe.baseServings,
                  prepMins: recipe.prepMins,
                  cookMins: recipe.cookMins,
                  difficulty: recipe.difficulty,
                  sourceUrl: recipe.sourceUrl,
                  ingredients: recipe.ingredients,
                  steps: recipe.steps,
                  isBatchCook: recipe.isBatchCook,
                  batchDishes: recipe.batchDishes,
                })}
                filename={recipe.title}
                locked={locked.markdownExport}
              />
            )}
            {isOwner && (
              <>
                {available.versionHistory && (
                  <VersionHistoryButton
                    recipeId={id}
                    currentSnapshot={{
                      title: recipe.title,
                      description: recipe.description,
                      ingredients: recipe.ingredients.map((ing) => ({
                        rawName: ing.rawName,
                        quantity: ing.quantity,
                        unit: ing.unit,
                        note: ing.note,
                      })),
                      steps: recipe.steps.map((s) => ({
                        instruction: s.instruction,
                        timerSeconds: s.timerSeconds,
                      })),
                    }}
                    locked={locked.versionHistory}
                  />
                )}
                <Tooltip>
                  <TooltipTrigger render={
                    <Link href={`/recipes/${id}/edit`} className={cn(buttonVariants({ variant: "ghost", size: "icon" }))}>
                      <Pencil className="h-4 w-4" />
                    </Link>
                  } />
                  <TooltipContent>{m.recipe.edit}</TooltipContent>
                </Tooltip>
                <DeleteRecipeButton recipeId={id} />
              </>
            )}
        </div>
        </TooltipProvider>

        {avgScore !== null && (
          <div className="flex items-center gap-2">
            <RatingStars recipeId={id} initialScore={Math.round(avgScore)} readonly size="sm" />
            <span className="text-sm text-muted-foreground">{avgScore.toFixed(1)} ({ratingCount})</span>
          </div>
        )}

        {recipe.description && (
          <p className="text-muted-foreground leading-relaxed">
            {recipe.isBatchCook ? stripMarkdown(recipe.description) : recipe.description}
          </p>
        )}

        {recipe.sourceUrl && (
          <a
            href={recipe.sourceUrl}
            target="_blank"
            rel="noopener noreferrer nofollow"
            className="inline-flex items-center gap-1 text-xs text-muted-foreground hover:text-foreground underline underline-offset-4"
          >
            <ExternalLink className="h-3 w-3" />
            {m.recipe.source}: {new URL(recipe.sourceUrl).hostname.replace(/^www\./, "")}
          </a>
        )}

        <div className="flex flex-wrap items-center gap-3 text-sm">
          {recipe.difficulty && (
            <Badge variant={DIFFICULTY_COLOR[recipe.difficulty]}>{m.recipe.difficulty[recipe.difficulty]}</Badge>
          )}
          <span className="flex items-center gap-1 text-muted-foreground">
            <Users className="h-4 w-4" />
            {formatMessage(m.recipe.servings, { count: recipe.baseServings })}
          </span>
          {recipe.prepMins && (
            <span className="flex items-center gap-1 text-muted-foreground">
              <Clock className="h-4 w-4" />
              {formatMessage(m.recipe.prep, { mins: recipe.prepMins })}
            </span>
          )}
          {recipe.cookMins && (
            <span className="flex items-center gap-1 text-muted-foreground">
              <ChefHat className="h-4 w-4" />
              {formatMessage(m.recipe.cook, { mins: recipe.cookMins })}
            </span>
          )}
          {totalMins > 0 && recipe.prepMins && recipe.cookMins && (
            <span className="text-muted-foreground">({formatMessage(m.recipe.total, { mins: totalMins })})</span>
          )}
          <span className="flex items-center gap-1 text-muted-foreground ml-auto">
            <VisibilityIcon className="h-4 w-4" />
            {VISIBILITY_LABEL[recipe.visibility]}
          </span>
        </div>

        {activeDietaryTags.length > 0 && (
          <div className="flex flex-wrap gap-1.5">
            {activeDietaryTags.map((tag) => (
              <Badge key={tag} variant="secondary" className="text-xs">{tag}</Badge>
            ))}
          </div>
        )}

        {recipe.tags.length > 0 && (
          <div className="flex flex-wrap gap-1.5">
            {recipe.tags.map((tag) => (
              <Badge key={tag} variant="outline" className="text-xs">{tag}</Badge>
            ))}
          </div>
        )}
      </div>

      {/* Cover photo */}
      {cover && (
        <div className="relative aspect-video overflow-hidden rounded-xl bg-muted">
          <Image
            src={getPublicUrl(cover.storageKey)}
            unoptimized
            alt={recipe.title}
            fill
            className="object-cover"
          />
        </div>
      )}

      <Separator />

      {/* Empty state */}
      {recipe.ingredients.length === 0 && recipe.steps.length === 0 && (
        <div className="flex flex-col items-center gap-4 py-12 text-center">
          <p className="text-muted-foreground">No ingredients or steps yet.</p>
          {isOwner && (
            <div className="flex items-center gap-2">
              <GenerateContentButton
                recipeId={id}
                title={recipe.title}
                description={recipe.description}
              />
              <Link href={`/recipes/${id}/edit`} className={cn(buttonVariants({ variant: "outline", size: "sm" }))}>
                <Pencil className="h-4 w-4" />
                Edit manually
              </Link>
            </div>
          )}
        </div>
      )}

      {/* Serving scaler + ingredients */}
      {recipe.ingredients.length > 0 && (
        <div className="space-y-4">
          <h2 className="text-xl font-semibold">{m.recipe.ingredients}</h2>
          <ServingScaler
            baseServings={recipe.baseServings}
            recipeTitle={recipe.title}
            unitPref={unitPref}
            ingredients={recipe.ingredients.map((ing) => ({
              id: ing.id,
              rawName: ing.rawName,
              quantity: ing.quantity,
              unit: ing.unit,
              note: ing.note,
              order: ing.order,
            }))}
          />
          <NutritionPanel
            recipeId={id}
            initialData={recipe.nutritionData}
            initialManual={recipe.nutritionManual}
            estimateAvailable={available.nutritionEstimation}
            estimateLocked={locked.nutritionEstimation}
          />
        </div>
      )}

      {recipe.steps.length > 0 && (
        <>
          <Separator />
          <div className="space-y-6">
            <h2 className="text-xl font-semibold">{m.recipe.instructions}</h2>
            {recipe.isBatchCook ? (
              <BatchCookSteps steps={recipe.steps} />
            ) : (
              <ol className="space-y-6">
                {recipe.steps.map((step, i) => (
                  <li key={step.id} className="flex gap-4">
                    <div className="flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-primary text-primary-foreground text-sm font-bold">
                      {i + 1}
                    </div>
                    <div className="flex-1 space-y-1 pt-1">
                      <p className="leading-relaxed">{step.instruction}</p>
                      {!!step.timerSeconds && (
                        <p className="text-xs text-muted-foreground flex items-center gap-1">
                          <Clock className="h-3 w-3" />
                          {step.timerSeconds >= 60
                            ? `${Math.floor(step.timerSeconds / 60)}m ${step.timerSeconds % 60 > 0 ? `${step.timerSeconds % 60}s` : ""}`
                            : `${step.timerSeconds}s`}
                        </p>
                      )}
                    </div>
                  </li>
                ))}
              </ol>
            )}
          </div>
        </>
      )}

      {recipe.isBatchCook && recipe.batchDishes.length > 0 && (
        <>
          <Separator />
          <BatchCookDishes
            recipeId={id}
            dishes={recipe.batchDishes.map((d) => ({ ...d, cookedAt: dishCookedAtMap.get(d.id) ?? null }))}
          />
        </>
      )}

      {recipe.photos.length > 1 && (
        <>
          <Separator />
          <div className="space-y-3">
            <h2 className="text-xl font-semibold">Photos</h2>
            <div className="grid grid-cols-3 gap-3">
              {recipe.photos.map((photo, i) => (
                <div key={photo.id} className="relative aspect-square rounded-lg overflow-hidden bg-muted">
                  <Image
                    src={getPublicUrl(photo.storageKey)}
                    unoptimized
                    alt={`${recipe.title} photo ${i + 1}`}
                    fill
                    className="object-cover"
                  />
                </div>
              ))}
            </div>
          </div>
        </>
      )}

      {!recipe.isBatchCook && (
        <>
          <Separator />
          <MarkCookedSection
            recipeId={id}
            baseServings={recipe.baseServings}
            initialLogs={plainCookLog}
          />
        </>
      )}

      {recipe.visibility !== "private" && (
        <>
          <Separator />
          <div className="space-y-4">
            {isOwner ? (
              <RatingStars recipeId={id} initialScore={myScore} readonly />
            ) : (
              <CookedItReview
                recipeId={id}
                initialScore={myScore}
                initialText={myRating?.reviewText ?? ""}
                initialPhotoKey={myRating?.photoKey ?? null}
              />
            )}
          </div>
          <Separator />
          <CommentsSection recipeId={id} currentUserId={session.user.id} />
        </>
      )}

      <Separator />
      <RecipeNotes recipeId={id} initialContent={myNote?.content ?? ""} />

      {featurePrefs.chatbots && <RecipeChatPanel recipeId={id} recipeTitle={recipe.title} />}
    </div>
  );
}
