"use client";

import { useState, useCallback, useEffect } from "react";
import Image from "next/image";
import { useTranslations } from "next-intl";
import { Trash2, Globe, Lock, Link2, X, Check, ListChecks, LayoutGrid, List, Rows3, FolderPlus, ChefHat, ExternalLink, Tag, Download, UserCheck } from "lucide-react";
import { AddToCollectionDialog } from "@/components/recipe/add-to-collection-dialog";
import { BulkTagsDialog } from "@/components/recipe/bulk-tags-dialog";
import { Button, buttonVariants } from "@/components/ui/button";
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogTitle,
} from "@/components/ui/alert-dialog";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
import { FavoriteButton } from "@/components/social/favorite-button";
import { RecipeCoverPlaceholder } from "@/components/recipe/recipe-cover-placeholder";
import { toast } from "sonner";
import { getPublicUrl } from "@/lib/storage";
import { useLocale } from "@/lib/i18n/provider";
import { Badge } from "@/components/ui/badge";
import { Clock, Users, Utensils } from "lucide-react";
import Link from "next/link";
import { cn, stripMarkdown } from "@/lib/utils";

type Recipe = {
  id: string;
  title: string;
  description: string | null;
  baseServings: number;
  prepMins: number | null;
  cookMins: number | null;
  difficulty: "easy" | "medium" | "hard" | null;
  visibility: "private" | "unlisted" | "public" | "followers";
  tags: string[];
  updatedAt: Date;
  photos?: Array<{ storageKey: string; isCover: boolean }>;
  coverIcon?: string | null;
  coverColor?: string | null;
  isFavorited?: boolean;
  isBatchCook?: boolean;
  dishCount?: number;
  sourceUrl?: string | null;
  recipeType?: "dish" | "drink";
};

/** Stops the click from bubbling to the card's own Link/select handler. */
function StopPropagation({ children }: { children: React.ReactNode }) {
  // preventDefault is required too — stopPropagation alone doesn't stop the ancestor
  // Link's native anchor navigation, since that's the browser's default action for the
  // click event reaching the <a>, not a bubbling JS handler stopPropagation can block.
  return <div onClick={(e) => { e.preventDefault(); e.stopPropagation(); }}>{children}</div>;
}

type ViewMode = "grid" | "list" | "compact";
const VIEW_STORAGE_KEY = "epicure-recipes-view";

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

function hostnameOf(url: string): string {
  try {
    return new URL(url).hostname.replace(/^www\./, "");
  } catch {
    return url;
  }
}

function RecipeThumb({ recipe, selectMode, selected, className }: { recipe: Recipe; selectMode: boolean; selected: boolean; className?: string }) {
  const cover = recipe.photos?.find((p) => p.isCover) ?? recipe.photos?.[0];
  return (
    <div className={cn("relative overflow-hidden bg-muted shrink-0", className)}>
      {cover ? (
        <Image
          src={getPublicUrl(cover.storageKey)}
          unoptimized
          alt={recipe.title}
          fill
          sizes="(max-width: 640px) 50vw, (max-width: 1024px) 33vw, 25vw"
          className={cn(
            "object-cover transition-transform duration-300",
            !selectMode && "group-hover:scale-105",
            selectMode && selected && "brightness-75"
          )}
        />
      ) : (
        <RecipeCoverPlaceholder
          recipe={recipe}
          className={cn(selectMode && !selected && "opacity-60")}
        />
      )}
      {selectMode && selected && <div className="absolute inset-0 bg-primary/20" />}
      {selectMode && (
        <div className={cn(
          "absolute top-1.5 left-1.5 h-5 w-5 rounded-full border-2 flex items-center justify-center transition-all duration-150 shadow-sm",
          selected ? "bg-primary border-primary" : "bg-black/30 border-white/70 group-hover:border-white"
        )}>
          {selected && <Check className="h-3 w-3 text-primary-foreground stroke-[3]" />}
        </div>
      )}
    </div>
  );
}

function GridCard({ recipe, selected, selectMode }: { recipe: Recipe; selected: boolean; selectMode: boolean }) {
  const t = useTranslations("recipe");
  const tBatch = useTranslations("batchCooking");
  const totalMins = (recipe.prepMins ?? 0) + (recipe.cookMins ?? 0);
  const VisibilityIcon = VISIBILITY_ICON[recipe.visibility];

  return (
    <div
      className={cn(
        "group relative overflow-hidden rounded-xl border bg-card flex flex-col h-full transition-all duration-200",
        selectMode && "cursor-pointer select-none",
        selected
          ? "ring-2 ring-primary border-primary shadow-lg shadow-primary/10"
          : selectMode
          ? "hover:border-muted-foreground/40"
          : "hover:shadow-md hover:border-muted-foreground/30"
      )}
    >
      <RecipeThumb recipe={recipe} selectMode={selectMode} selected={selected} className="aspect-video" />
      <div className="flex flex-col flex-1 p-3 gap-1">
        <h3 className={cn("font-semibold leading-tight line-clamp-2 text-sm transition-colors", !selectMode && "group-hover:text-primary")}>
          {recipe.title}
        </h3>
        {recipe.description && (
          <p className="text-xs text-muted-foreground line-clamp-2 leading-relaxed">
            {recipe.isBatchCook ? stripMarkdown(recipe.description) : recipe.description}
          </p>
        )}
        {recipe.tags.length > 0 && (
          <div className="flex flex-wrap gap-1 mt-1">
            {recipe.tags.slice(0, 3).map((tag) => (
              <span key={tag} className="inline-flex items-center px-1.5 py-0.5 rounded text-xs bg-muted text-muted-foreground">
                {tag}
              </span>
            ))}
            {recipe.tags.length > 3 && (
              <span className="inline-flex items-center px-1.5 py-0.5 rounded text-xs text-muted-foreground">+{recipe.tags.length - 3}</span>
            )}
          </div>
        )}
      </div>
      <div className="px-3 pb-3 flex items-center justify-between text-xs text-muted-foreground">
        <div className="flex items-center gap-2.5">
          {recipe.isBatchCook && recipe.dishCount ? (
            <span className="flex items-center gap-1"><Utensils className="h-3 w-3" />{tBatch("dishCount", { count: recipe.dishCount })}</span>
          ) : (
            <span className="flex items-center gap-1"><Users className="h-3 w-3" />{recipe.baseServings}</span>
          )}
          {totalMins > 0 && <span className="flex items-center gap-1"><Clock className="h-3 w-3" />{t("total", { mins: totalMins })}</span>}
          {recipe.difficulty && (
            <Badge variant={DIFFICULTY_COLOR[recipe.difficulty]} className="text-xs h-4 px-1.5">{t(`difficulty.${recipe.difficulty}`)}</Badge>
          )}
        </div>
        <div className="flex items-center gap-1 shrink-0">
          {recipe.sourceUrl && (
            <TooltipProvider>
              <Tooltip>
                <TooltipTrigger render={<span className="p-1.5 inline-flex"><ExternalLink className="h-3.5 w-3.5 text-muted-foreground" /></span>} />
                <TooltipContent>{t("importedFrom", { host: hostnameOf(recipe.sourceUrl) })}</TooltipContent>
              </Tooltip>
            </TooltipProvider>
          )}
          {recipe.isBatchCook && (
            <TooltipProvider>
              <Tooltip>
                <TooltipTrigger render={<span className="p-1.5 inline-flex"><ChefHat className="h-3.5 w-3.5 text-muted-foreground" /></span>} />
                <TooltipContent>{t("batchCookBadge")}</TooltipContent>
              </Tooltip>
            </TooltipProvider>
          )}
          {!selectMode && (
            <StopPropagation>
              <FavoriteButton recipeId={recipe.id} initialFavorited={recipe.isFavorited} />
            </StopPropagation>
          )}
          <TooltipProvider>
            <Tooltip>
              <TooltipTrigger render={<span className="p-1.5 inline-flex"><VisibilityIcon className="h-3 w-3" /></span>} />
              <TooltipContent>{t(`visibility.${recipe.visibility}`)}</TooltipContent>
            </Tooltip>
          </TooltipProvider>
        </div>
      </div>
    </div>
  );
}

function ListRow({ recipe, selected, selectMode }: { recipe: Recipe; selected: boolean; selectMode: boolean }) {
  const t = useTranslations("recipe");
  const tBatch = useTranslations("batchCooking");
  const { locale } = useLocale();
  const totalMins = (recipe.prepMins ?? 0) + (recipe.cookMins ?? 0);
  const VisibilityIcon = VISIBILITY_ICON[recipe.visibility];

  return (
    <div
      className={cn(
        "group flex gap-4 p-3 rounded-xl border bg-card transition-all duration-200",
        selectMode && "cursor-pointer select-none",
        selected ? "ring-2 ring-primary border-primary shadow-sm shadow-primary/10" : selectMode ? "hover:border-muted-foreground/40" : "hover:shadow-md hover:border-muted-foreground/30"
      )}
    >
      <RecipeThumb recipe={recipe} selectMode={selectMode} selected={selected} className="w-28 h-20 rounded-lg" />
      <div className="flex-1 min-w-0 flex flex-col gap-1">
        <div className="flex items-start justify-between gap-2">
          <h3 className={cn("font-semibold leading-tight line-clamp-1 text-sm", !selectMode && "group-hover:text-primary")}>
            {recipe.title}
          </h3>
          <div className="flex items-center gap-1 shrink-0">
            {recipe.sourceUrl && (
              <TooltipProvider>
                <Tooltip>
                  <TooltipTrigger render={<span className="p-1.5 inline-flex"><ExternalLink className="h-3.5 w-3.5 text-muted-foreground" /></span>} />
                  <TooltipContent>{t("importedFrom", { host: hostnameOf(recipe.sourceUrl) })}</TooltipContent>
                </Tooltip>
              </TooltipProvider>
            )}
            {recipe.isBatchCook && (
              <TooltipProvider>
                <Tooltip>
                  <TooltipTrigger render={<span className="p-1.5 inline-flex"><ChefHat className="h-3.5 w-3.5 text-muted-foreground" /></span>} />
                  <TooltipContent>{t("batchCookBadge")}</TooltipContent>
                </Tooltip>
              </TooltipProvider>
            )}
            {!selectMode && (
              <StopPropagation>
                <FavoriteButton recipeId={recipe.id} initialFavorited={recipe.isFavorited} />
              </StopPropagation>
            )}
            <TooltipProvider>
              <Tooltip>
                <TooltipTrigger render={<span className="p-1.5 inline-flex"><VisibilityIcon className="h-3.5 w-3.5 text-muted-foreground" /></span>} />
                <TooltipContent>{t(`visibility.${recipe.visibility}`)}</TooltipContent>
              </Tooltip>
            </TooltipProvider>
          </div>
        </div>
        {recipe.description && <p className="text-xs text-muted-foreground line-clamp-2 leading-relaxed">{recipe.isBatchCook ? stripMarkdown(recipe.description) : recipe.description}</p>}
        <div className="flex items-center gap-2.5 text-xs text-muted-foreground mt-auto flex-wrap">
          {recipe.isBatchCook && recipe.dishCount ? (
            <span className="flex items-center gap-1"><Utensils className="h-3 w-3" />{tBatch("dishCount", { count: recipe.dishCount })}</span>
          ) : (
            <span className="flex items-center gap-1"><Users className="h-3 w-3" />{recipe.baseServings}</span>
          )}
          {totalMins > 0 && <span className="flex items-center gap-1"><Clock className="h-3 w-3" />{t("total", { mins: totalMins })}</span>}
          {recipe.difficulty && <Badge variant={DIFFICULTY_COLOR[recipe.difficulty]} className="text-xs h-4 px-1.5">{t(`difficulty.${recipe.difficulty}`)}</Badge>}
          {recipe.tags.slice(0, 2).map((tag) => (
            <span key={tag} className="px-1.5 py-0.5 rounded bg-muted">{tag}</span>
          ))}
          <span className="ml-auto shrink-0">{t("updatedLabel", { date: recipe.updatedAt.toLocaleDateString(locale, { month: "short", day: "numeric" }) })}</span>
        </div>
      </div>
    </div>
  );
}

function CompactRow({ recipe, selected, selectMode }: { recipe: Recipe; selected: boolean; selectMode: boolean }) {
  const t = useTranslations("recipe");
  const tBatch = useTranslations("batchCooking");
  const { locale } = useLocale();
  const totalMins = (recipe.prepMins ?? 0) + (recipe.cookMins ?? 0);
  const VisibilityIcon = VISIBILITY_ICON[recipe.visibility];

  return (
    <div
      className={cn(
        "group flex items-center gap-3 px-3 py-2 rounded-lg border bg-card transition-all duration-150",
        selectMode && "cursor-pointer select-none",
        selected ? "ring-2 ring-primary border-primary" : selectMode ? "hover:border-muted-foreground/40" : "hover:bg-muted/40"
      )}
    >
      <RecipeThumb recipe={recipe} selectMode={selectMode} selected={selected} className="w-10 h-10 rounded-md shrink-0" />
      <h3 className={cn("font-medium text-sm truncate flex-1 min-w-0", !selectMode && "group-hover:text-primary")}>
        {recipe.title}
      </h3>
      <span className="hidden sm:flex items-center gap-1 text-xs text-muted-foreground shrink-0 w-16">
        {recipe.isBatchCook && recipe.dishCount ? (
          <><Utensils className="h-3 w-3" />{tBatch("dishCount", { count: recipe.dishCount })}</>
        ) : (
          <><Users className="h-3 w-3" />{recipe.baseServings}</>
        )}
      </span>
      <span className="hidden sm:flex items-center gap-1 text-xs text-muted-foreground shrink-0 w-20">
        {totalMins > 0 && (<><Clock className="h-3 w-3" />{t("total", { mins: totalMins })}</>)}
      </span>
      <span className="hidden sm:inline-flex w-16 shrink-0">
        {recipe.difficulty && (
          <Badge variant={DIFFICULTY_COLOR[recipe.difficulty]} className="text-xs h-4 px-1.5">{t(`difficulty.${recipe.difficulty}`)}</Badge>
        )}
      </span>
      <span className="hidden md:inline text-xs text-muted-foreground shrink-0 w-16 text-right">
        {recipe.updatedAt.toLocaleDateString(locale, { month: "short", day: "numeric" })}
      </span>
      {recipe.sourceUrl && (
        <TooltipProvider>
          <Tooltip>
            <TooltipTrigger render={<span className="p-1.5 inline-flex shrink-0"><ExternalLink className="h-3.5 w-3.5 text-muted-foreground" /></span>} />
            <TooltipContent>{t("importedFrom", { host: hostnameOf(recipe.sourceUrl) })}</TooltipContent>
          </Tooltip>
        </TooltipProvider>
      )}
      {recipe.isBatchCook && (
        <TooltipProvider>
          <Tooltip>
            <TooltipTrigger render={<span className="p-1.5 inline-flex shrink-0"><ChefHat className="h-3.5 w-3.5 text-muted-foreground" /></span>} />
            <TooltipContent>{t("batchCookBadge")}</TooltipContent>
          </Tooltip>
        </TooltipProvider>
      )}
      {!selectMode && (
        <StopPropagation>
          <FavoriteButton recipeId={recipe.id} initialFavorited={recipe.isFavorited} />
        </StopPropagation>
      )}
      <TooltipProvider>
        <Tooltip>
          <TooltipTrigger render={<span className="p-1.5 inline-flex shrink-0"><VisibilityIcon className="h-3.5 w-3.5 text-muted-foreground" /></span>} />
          <TooltipContent>{t(`visibility.${recipe.visibility}`)}</TooltipContent>
        </Tooltip>
      </TooltipProvider>
    </div>
  );
}

function SelectableRecipe({
  recipe,
  selected,
  selectMode,
  viewMode,
  onToggle,
}: {
  recipe: Recipe;
  selected: boolean;
  selectMode: boolean;
  viewMode: ViewMode;
  onToggle: (id: string) => void;
}) {
  const Tile = viewMode === "grid" ? GridCard : viewMode === "list" ? ListRow : CompactRow;
  const inner = <Tile recipe={recipe} selected={selected} selectMode={selectMode} />;

  if (selectMode) {
    return (
      <div onClick={() => onToggle(recipe.id)} role="checkbox" aria-checked={selected} className="h-full">
        {inner}
      </div>
    );
  }

  return (
    <Link href={`/recipes/${recipe.id}`} className="h-full block">
      {inner}
    </Link>
  );
}

function ViewToggle({ value, onChange }: { value: ViewMode; onChange: (v: ViewMode) => void }) {
  const t = useTranslations("recipe");
  const options: { mode: ViewMode; icon: typeof LayoutGrid; label: string }[] = [
    { mode: "grid", icon: LayoutGrid, label: t("viewGrid") },
    { mode: "list", icon: List, label: t("viewList") },
    { mode: "compact", icon: Rows3, label: t("viewCompact") },
  ];

  return (
    <TooltipProvider>
      <div className="inline-flex items-center rounded-lg border p-0.5 gap-0.5">
        {options.map(({ mode, icon: Icon, label }) => (
          <Tooltip key={mode}>
            <TooltipTrigger render={
              <button
                onClick={() => onChange(mode)}
                aria-label={label}
                aria-pressed={value === mode}
                className={cn(
                  "flex items-center justify-center h-7 w-7 rounded-md transition-colors",
                  value === mode ? "bg-accent text-accent-foreground" : "text-muted-foreground hover:text-foreground hover:bg-accent/50"
                )}
              />
            }>
              <Icon className="h-4 w-4" />
            </TooltipTrigger>
            <TooltipContent>{label}</TooltipContent>
          </Tooltip>
        ))}
      </div>
    </TooltipProvider>
  );
}

export function RecipesGrid({ recipes: initialRecipes }: { recipes: Recipe[] }) {
  const t = useTranslations("recipe");
  const tCommon = useTranslations("common");
  const [recipes, setRecipes] = useState(initialRecipes);
  const [selectMode, setSelectMode] = useState(false);
  const [selected, setSelected] = useState<Set<string>>(new Set());
  const [busy, setBusy] = useState(false);
  const [viewMode, setViewMode] = useState<ViewMode>("grid");
  const [addToCollectionOpen, setAddToCollectionOpen] = useState(false);
  const [deleteConfirmOpen, setDeleteConfirmOpen] = useState(false);
  const [bulkTagsOpen, setBulkTagsOpen] = useState(false);
  const [exporting, setExporting] = useState(false);

  useEffect(() => {
    const stored = localStorage.getItem(VIEW_STORAGE_KEY) as ViewMode | null;
    if (stored === "grid" || stored === "list" || stored === "compact") setViewMode(stored);
  }, []);

  function changeViewMode(mode: ViewMode) {
    setViewMode(mode);
    localStorage.setItem(VIEW_STORAGE_KEY, mode);
  }

  const toggleSelect = useCallback((id: string) => {
    setSelected((prev) => {
      const next = new Set(prev);
      next.has(id) ? next.delete(id) : next.add(id);
      return next;
    });
  }, []);

  const toggleAll = () => {
    setSelected((prev) => (prev.size === recipes.length ? new Set() : new Set(recipes.map((r) => r.id))));
  };

  const exitSelect = () => {
    setSelectMode(false);
    setSelected(new Set());
  };

  async function bulkDelete() {
    setBusy(true);
    try {
      const res = await fetch("/api/v1/recipes/bulk", {
        method: "DELETE",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ ids: [...selected] }),
      });
      if (!res.ok) throw new Error("Delete failed");
      setRecipes((prev) => prev.filter((r) => !selected.has(r.id)));
      toast.success(t("bulkDeleted", { count: selected.size }));
      exitSelect();
    } catch {
      toast.error(t("bulkDeleteFailed"));
    } finally {
      setBusy(false);
    }
  }

  async function bulkSetVisibility(visibility: "private" | "unlisted" | "public" | "followers") {
    setBusy(true);
    try {
      const res = await fetch("/api/v1/recipes/bulk", {
        method: "PATCH",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ ids: [...selected], visibility }),
      });
      if (!res.ok) throw new Error("Update failed");
      setRecipes((prev) => prev.map((r) => (selected.has(r.id) ? { ...r, visibility } : r)));
      toast.success(t("bulkVisibility", { count: selected.size, visibility }));
      exitSelect();
    } catch {
      toast.error(t("bulkUpdateFailed"));
    } finally {
      setBusy(false);
    }
  }

  function applyBulkTags(addTags: string[], removeTags: string[]) {
    setRecipes((prev) =>
      prev.map((r) =>
        selected.has(r.id)
          ? { ...r, tags: [...new Set([...r.tags.filter((tag) => !removeTags.includes(tag)), ...addTags])] }
          : r
      )
    );
    exitSelect();
  }

  async function bulkExport() {
    setExporting(true);
    try {
      const res = await fetch("/api/v1/recipes/bulk/export", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ ids: [...selected] }),
      });
      if (!res.ok) throw new Error();
      const { markdown } = (await res.json()) as { markdown: string };
      const blob = new Blob([markdown], { type: "text/markdown;charset=utf-8" });
      const url = URL.createObjectURL(blob);
      const a = document.createElement("a");
      a.href = url;
      a.download = "recipes.md";
      document.body.appendChild(a);
      a.click();
      a.remove();
      URL.revokeObjectURL(url);
    } catch {
      toast.error(t("bulkExportFailed"));
    } finally {
      setExporting(false);
    }
  }

  if (recipes.length === 0) return null;

  const allSelected = selected.size === recipes.length;
  const availableTagsForRemoval = [...new Set(recipes.filter((r) => selected.has(r.id)).flatMap((r) => r.tags))];

  return (
    <div className="space-y-4">
      {/* Toolbar */}
      <div className={cn("flex items-center min-h-[36px] gap-3", selectMode && "justify-between")}>
        {selectMode && (
          <div className="flex items-center gap-3">
            <button onClick={toggleAll} className="text-sm font-medium text-primary hover:underline">
              {allSelected ? t("deselectAll") : t("selectAll")}
            </button>
            <span className="text-sm text-muted-foreground">
              {selected.size > 0 ? t("selectedCount", { count: selected.size }) : t("clickToSelect")}
            </span>
          </div>
        )}
        <div className="flex items-center gap-2">
          <ViewToggle value={viewMode} onChange={changeViewMode} />
          <Button
            variant="ghost"
            size="sm"
            onClick={selectMode ? exitSelect : () => setSelectMode(true)}
            className={cn("gap-1.5", selectMode && "text-muted-foreground")}
          >
            {selectMode ? (
              <><X className="h-4 w-4" />{tCommon("cancel")}</>
            ) : (
              <><ListChecks className="h-4 w-4" />{t("select")}</>
            )}
          </Button>
        </div>
      </div>

      {/* Recipes */}
      <div
        className={cn(
          viewMode === "grid" && "grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4 items-start",
          viewMode === "list" && "flex flex-col gap-3",
          viewMode === "compact" && "flex flex-col gap-1.5"
        )}
      >
        {recipes.map((recipe) => (
          <SelectableRecipe
            key={recipe.id}
            recipe={recipe}
            selected={selected.has(recipe.id)}
            selectMode={selectMode}
            viewMode={viewMode}
            onToggle={toggleSelect}
          />
        ))}
      </div>

      {/* Floating bulk action bar */}
      {selectMode && selected.size > 0 && (
        <div className="fixed bottom-4 sm:bottom-8 left-1/2 -translate-x-1/2 z-50 w-[calc(100vw-2rem)] sm:w-auto sm:max-w-none animate-in slide-in-from-bottom-4 duration-200">
          <div className="flex items-center gap-1 sm:gap-2 bg-popover border shadow-2xl rounded-2xl px-2 sm:px-5 py-2 sm:py-3 overflow-x-auto sm:overflow-visible [scrollbar-width:none] [-ms-overflow-style:none] [&::-webkit-scrollbar]:hidden">
            <span className="text-sm font-semibold tabular-nums mr-1 shrink-0">{selected.size}</span>
            <div className="w-px h-5 bg-border mx-1 shrink-0" />
            <DropdownMenu>
              <DropdownMenuTrigger disabled={busy} className={buttonVariants({ variant: "ghost", size: "sm" }) + " gap-1.5 shrink-0"} aria-label={t("visibilityMenuLabel")}>
                <Globe className="h-4 w-4" />
                <span className="hidden sm:inline">{t("visibilityMenuLabel")}</span>
              </DropdownMenuTrigger>
              <DropdownMenuContent align="center" side="top">
                <DropdownMenuItem onClick={() => { void bulkSetVisibility("public"); }}>
                  <Globe className="h-4 w-4 mr-2 text-green-500" /> {t("makePublic")}
                </DropdownMenuItem>
                <DropdownMenuItem onClick={() => { void bulkSetVisibility("unlisted"); }}>
                  <Link2 className="h-4 w-4 mr-2 text-yellow-500" /> {t("makeUnlisted")}
                </DropdownMenuItem>
                <DropdownMenuItem onClick={() => { void bulkSetVisibility("followers"); }}>
                  <UserCheck className="h-4 w-4 mr-2 text-blue-500" /> {t("makeFollowersOnly")}
                </DropdownMenuItem>
                <DropdownMenuItem onClick={() => { void bulkSetVisibility("private"); }}>
                  <Lock className="h-4 w-4 mr-2 text-muted-foreground" /> {t("makePrivate")}
                </DropdownMenuItem>
              </DropdownMenuContent>
            </DropdownMenu>
            <Button variant="ghost" size="sm" onClick={() => setAddToCollectionOpen(true)} disabled={busy} className="gap-1.5 shrink-0" aria-label={t("addToCollection")}>
              <FolderPlus className="h-4 w-4" />
              <span className="hidden sm:inline">{t("addToCollection")}</span>
            </Button>
            <Button variant="ghost" size="sm" onClick={() => setBulkTagsOpen(true)} disabled={busy} className="gap-1.5 shrink-0" aria-label={t("bulkTagsButton")}>
              <Tag className="h-4 w-4" />
              <span className="hidden sm:inline">{t("bulkTagsButton")}</span>
            </Button>
            <Button variant="ghost" size="sm" onClick={() => { void bulkExport(); }} disabled={exporting || busy} className="gap-1.5 shrink-0" aria-label={t("bulkExportButton")}>
              <Download className="h-4 w-4" />
              <span className="hidden sm:inline">{t("bulkExportButton")}</span>
            </Button>
            <Button variant="destructive" size="sm" onClick={() => setDeleteConfirmOpen(true)} disabled={busy} className="gap-1.5 shrink-0" aria-label={tCommon("delete")}>
              <Trash2 className="h-4 w-4" />
              <span className="hidden sm:inline">{tCommon("delete")}</span>
            </Button>
          </div>
        </div>
      )}

      <AddToCollectionDialog
        open={addToCollectionOpen}
        onOpenChange={setAddToCollectionOpen}
        recipeIds={[...selected]}
        onDone={exitSelect}
      />

      <BulkTagsDialog
        open={bulkTagsOpen}
        onOpenChange={setBulkTagsOpen}
        recipeIds={[...selected]}
        availableTags={availableTagsForRemoval}
        onDone={applyBulkTags}
      />

      <AlertDialog open={deleteConfirmOpen} onOpenChange={setDeleteConfirmOpen}>
        <AlertDialogContent>
          <AlertDialogHeader>
            <AlertDialogTitle>{t("bulkDeleteConfirmTitle", { count: selected.size })}</AlertDialogTitle>
            <AlertDialogDescription>{t("bulkDeleteConfirmDescription")}</AlertDialogDescription>
          </AlertDialogHeader>
          <AlertDialogFooter>
            <AlertDialogCancel>{tCommon("cancel")}</AlertDialogCancel>
            <AlertDialogAction
              onClick={() => { setDeleteConfirmOpen(false); void bulkDelete(); }}
              className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
            >
              {tCommon("delete")}
            </AlertDialogAction>
          </AlertDialogFooter>
        </AlertDialogContent>
      </AlertDialog>
    </div>
  );
}
