import { useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import { CheckSquare, Square, UtensilsCrossed } from "lucide-react";
import { useRecipes } from "@/hooks/useRecipes";
import { useDebouncedValue } from "@/hooks/useDebouncedValue";
import { RecipeCard } from "@/components/recipes/RecipeCard";
import { RecipeFilters, type CategoryFilter } from "@/components/recipes/RecipeFilters";
import { PdfGenerator } from "@/components/pdf/PdfGenerator";
import { GridSkeleton } from "@/components/ui/Skeleton";
import { EmptyState } from "@/components/ui/EmptyState";
import { ErrorState } from "@/components/ui/ErrorState";
import { extractApiError } from "@/api/axiosInstance";
import { nextSort, sortBy, sortIndicator, type SortDirection } from "@/utils/sort.util";

type RecipeSortColumn = "name" | "calories" | "prepTime";

const RECIPE_SORT_COLUMNS: { id: RecipeSortColumn; labelKey: string }[] = [
  { id: "name", labelKey: "manage.recipeName" },
  { id: "calories", labelKey: "recipes.calories" },
  { id: "prepTime", labelKey: "manage.prepTimeMin" },
];

export function AllMealsPage() {
  const { t } = useTranslation();
  const [filter, setFilter] = useState<CategoryFilter>("all");
  const [search, setSearch] = useState("");
  const [searchByIngredient, setSearchByIngredient] = useState(false);
  const [selected, setSelected] = useState<Set<number>>(new Set());
  const [recipeSort, setRecipeSort] = useState<{ column: RecipeSortColumn; direction: SortDirection }>({
    column: "name",
    direction: "asc",
  });

  const debouncedSearch = useDebouncedValue(search.trim(), 350);
  const ingredientTerm = searchByIngredient && debouncedSearch ? debouncedSearch : undefined;

  const { data: recipes, isLoading, isError, error, refetch } = useRecipes(
    undefined,
    undefined,
    ingredientTerm,
  );

  const visible = useMemo(() => {
    if (!recipes) return [];
    const term = search.trim().toLowerCase();
    return recipes.filter((r) => {
      const matchesCategory = filter === "all" || r.mealCategory === filter;
      const matchesSearch = searchByIngredient || term === "" || r.name.toLowerCase().includes(term);
      return matchesCategory && matchesSearch;
    });
  }, [recipes, filter, search, searchByIngredient]);

  const sortedVisible = useMemo(() => {
    const { column, direction } = recipeSort;
    return sortBy(visible, direction, (recipe) => {
      switch (column) {
        case "name":
          return recipe.name;
        case "calories":
          return recipe.calories;
        case "prepTime":
          return recipe.prepTimeMinutes;
      }
    });
  }, [visible, recipeSort]);

  const toggleRecipeSort = (column: RecipeSortColumn) => {
    setRecipeSort((current) => nextSort(current, column));
  };

  const toggleSelected = (id: number) => {
    setSelected((prev) => {
      const next = new Set(prev);
      if (next.has(id)) {
        next.delete(id);
      } else {
        next.add(id);
      }
      return next;
    });
  };

  const selectAllVisible = () => {
    setSelected((prev) => {
      const next = new Set(prev);
      visible.forEach((r) => next.add(r.id));
      return next;
    });
  };

  const deselectAll = () => setSelected(new Set());

  const selectedIds = useMemo(() => Array.from(selected), [selected]);

  return (
    <div className="space-y-6">
      <header className="flex flex-wrap items-end justify-between gap-4">
        <div>
          <h1 className="text-2xl font-extrabold tracking-tight sm:text-3xl">{t("recipes.allMealsTitle")}</h1>
          <p className="mt-1 text-slate-500 dark:text-slate-400">{t("recipes.allMealsSubtitle")}</p>
        </div>
        <span className="inline-flex items-center gap-2 rounded-full bg-brand-100 px-3.5 py-1.5 text-sm font-semibold text-brand-800 dark:bg-brand-900/40 dark:text-brand-300">
          {t("common.selectedCount", { count: selected.size })}
        </span>
      </header>

      <RecipeFilters
        active={filter}
        onChange={setFilter}
        search={search}
        onSearchChange={setSearch}
        searchByIngredient={searchByIngredient}
        onSearchByIngredientChange={setSearchByIngredient}
      />

      <div className="flex flex-wrap items-center gap-3">
        <button
          type="button"
          onClick={selectAllVisible}
          disabled={visible.length === 0}
          className="btn-secondary"
        >
          <CheckSquare className="h-4 w-4" />
          {t("recipes.selectAllVisible")}
        </button>
        <button
          type="button"
          onClick={deselectAll}
          disabled={selected.size === 0}
          className="btn-secondary"
        >
          <Square className="h-4 w-4" />
          {t("recipes.deselectAll")}
        </button>
        <div className="ml-auto">
          <PdfGenerator selectedIds={selectedIds} />
        </div>
      </div>

      {isLoading && <GridSkeleton count={9} />}

      {isError && (
        <ErrorState
          message={extractApiError(error, t("errors.loadRecipesFailed"))}
          onRetry={() => void refetch()}
        />
      )}

      {!isLoading && !isError && visible.length === 0 && (
        <EmptyState
          icon={UtensilsCrossed}
          title={t("recipes.noMatchingTitle")}
          description={
            searchByIngredient ? t("recipes.noMatchingIngredient") : t("recipes.noMatchingFilter")
          }
        />
      )}

      {!isLoading && !isError && visible.length > 0 && (
        <>
          <div className="flex flex-wrap gap-2 text-sm">
            {RECIPE_SORT_COLUMNS.map(({ id, labelKey }) => (
              <button
                key={id}
                type="button"
                onClick={() => toggleRecipeSort(id)}
                className="rounded-lg border border-slate-200 px-3 py-1.5 font-medium hover:bg-slate-50 dark:border-slate-700 dark:hover:bg-slate-800"
              >
                {t(labelKey)}
                {sortIndicator(recipeSort, id)}
              </button>
            ))}
          </div>
          <div className="grid grid-cols-1 gap-5 sm:grid-cols-2 lg:grid-cols-3">
            {sortedVisible.map((recipe) => (
              <RecipeCard
                key={recipe.id}
                recipe={recipe}
                selectable
                showCategory
                selected={selected.has(recipe.id)}
                onToggleSelected={toggleSelected}
              />
            ))}
          </div>
        </>
      )}
    </div>
  );
}
