import {
  INGREDIENT_CATEGORIES,
  INGREDIENT_CATEGORY_SUBCATEGORIES,
  type IngredientCategory,
  type IngredientSubcategory,
  type IngredientView,
} from "@batch-cooking/shared";
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { CheckboxOption } from "../../../components/ui/Checkbox";
import { SettingsIcon } from "../../../layouts/nav-icons";
import { AllergenBadges } from "../badges/AllergenBadges";
import { DietBadges } from "../badges/DietBadges";
import { ReproducibleBadge } from "../badges/ReproducibleBadge";
import { CategoryIcon, IngredientTypeIcon, SubcategoryIcon } from "./ingredient-icons";
import { ingredientLabel } from "./ingredient-label";
import "../recipes.scss";

/** "No filter at this level" — a UI-only pseudo-value, never sent to/received from the API (see {@link INGREDIENT_CATEGORIES}/{@link INGREDIENT_CATEGORY_SUBCATEGORIES} for the real, closed sets). */
const ALL = "ALL" as const;

/**
 * Browsable ingredient picker — a two-level category/subcategory drill-down
 * plus search plus a card grid, replacing the earlier `IngredientAutocomplete`
 * (a plain type-to-filter dropdown). With 400+ reference ingredients, search
 * alone doesn't scale to actually *finding* one, and a single flat list of
 * 7 aisles wouldn't either (some — "Condiments & épices" — are 100+ items
 * deep) — so picking a category reveals a second row of subcategory chips
 * scoped to it (reset whenever the category changes, since a subcategory
 * from the previous one wouldn't apply). Search still narrows within (or
 * across) whatever's selected for when the name is already known.
 *
 * Receives `ingredients` as a prop rather than fetching them itself — same
 * rationale as `AllergySelect`/`DietSelect`. `excludeIds` (already-selected
 * ingredients — a recipe's ingredient list, or a profile's disliked list)
 * keeps the same one from being added twice.
 *
 * The settings menu trailing the search input shows/hides the allergen/diet
 * badge rows on every card — a display preference local to this picker (not
 * persisted), for whoever finds two rows of badges per card too noisy while
 * just browsing/searching by name. A labeled checkbox menu rather than two
 * bare icon-only toggle buttons — those turned out too ambiguous on their
 * own (unclear what each icon meant without a label attached).
 *
 * `onAddPlaceholder`, when passed, turns the "aucun ingrédient trouvé"
 * empty state into an escape hatch: with a non-empty search query, an
 * "ajouter « … » comme ingrédient à compléter" button lets the user add a
 * free-text line so the catalog gap doesn't block them (see
 * `Ingredient.isPlaceholder` in schema.prisma). Omitted on pickers where
 * that makes no sense — a profile's disliked-ingredients field, a search
 * filter.
 */
export function IngredientPicker({
  ingredients,
  excludeIds,
  onSelect,
  onAddPlaceholder,
}: {
  ingredients: IngredientView[];
  excludeIds: number[];
  onSelect: (ingredient: IngredientView) => void;
  onAddPlaceholder?: (name: string) => void;
}) {
  const { t } = useTranslation();
  const [category, setCategory] = useState<IngredientCategory | typeof ALL>(ALL);
  const [subcategory, setSubcategory] = useState<IngredientSubcategory | typeof ALL>(ALL);
  const [query, setQuery] = useState("");
  // Purely a display preference for this picker's own card grid — doesn't
  // touch which ingredients `visible` includes, only whether their
  // allergen/diet badges render. Defaults to shown (the previous, only
  // behavior); collapsing them is an opt-in for whoever finds two rows of
  // badges per card too noisy while just browsing/searching by name.
  const [showAllergens, setShowAllergens] = useState(true);
  const [showDiets, setShowDiets] = useState(true);
  const [showReproducible, setShowReproducible] = useState(true);
  const [isDisplayMenuOpen, setIsDisplayMenuOpen] = useState(false);

  function selectCategory(next: IngredientCategory | typeof ALL) {
    setCategory(next);
    setSubcategory(ALL);
  }

  const normalizedQuery = query.trim().toLowerCase();
  const visible = ingredients.filter((ingredient) => {
    if (excludeIds.includes(ingredient.id)) return false;
    if (category !== ALL) {
      if (ingredient.category !== category) return false;
      if (subcategory !== ALL && ingredient.subcategory !== subcategory) return false;
    }
    // Matches against the *displayed* (translated) label, not the raw slug
    // key — searching "œuf" should find "Œuf" the way it always has, not
    // require typing its key.
    if (normalizedQuery.length > 0) {
      const label = ingredientLabel(ingredient, t).toLowerCase();
      if (!label.includes(normalizedQuery)) return false;
    }
    return true;
  });

  const trimmedQuery = query.trim();

  function handleSelect(ingredient: IngredientView) {
    onSelect(ingredient);
    setQuery("");
  }

  function handleAddPlaceholder() {
    if (onAddPlaceholder && trimmedQuery.length > 0) {
      onAddPlaceholder(trimmedQuery);
      setQuery("");
    }
  }

  return (
    <div className="ingredient-picker">
      <div className="ingredient-picker__search">
        <input
          type="text"
          value={query}
          onChange={(e) => setQuery(e.target.value)}
          placeholder={t("recipes.form.searchIngredientPlaceholder")}
        />
        <div className="ingredient-picker__display-options">
          <button
            type="button"
            className={`ingredient-picker__display-toggle${isDisplayMenuOpen ? " active" : ""}`}
            onClick={() => setIsDisplayMenuOpen((v) => !v)}
            aria-expanded={isDisplayMenuOpen}
            title={t("recipes.form.displayOptions")}
          >
            <SettingsIcon aria-hidden="true" />
          </button>
          {isDisplayMenuOpen && (
            <div className="ingredient-picker__display-menu">
              <CheckboxOption checked={showDiets} onChange={setShowDiets}>
                {t("recipes.form.showDietsLabel")}
              </CheckboxOption>
              <CheckboxOption checked={showAllergens} onChange={setShowAllergens}>
                {t("recipes.form.showAllergensLabel")}
              </CheckboxOption>
              <CheckboxOption checked={showReproducible} onChange={setShowReproducible}>
                {t("recipes.form.showReproducibleLabel")}
              </CheckboxOption>
            </div>
          )}
        </div>
      </div>

      <div className="ingredient-picker__categories">
        <button
          type="button"
          className={`ingredient-picker__category${category === ALL ? " active" : ""}`}
          onClick={() => selectCategory(ALL)}
        >
          {t("recipes.form.allCategories")}
        </button>
        {INGREDIENT_CATEGORIES.map((c) => (
          <button
            key={c}
            type="button"
            className={`ingredient-picker__category${category === c ? " active" : ""}`}
            onClick={() => selectCategory(c)}
          >
            <CategoryIcon category={c} />
            {t(`recipes.form.category.${c}`)}
          </button>
        ))}
      </div>

      {category !== ALL && (
        <div className="ingredient-picker__subcategories">
          <button
            type="button"
            className={`ingredient-picker__subcategory${subcategory === ALL ? " active" : ""}`}
            onClick={() => setSubcategory(ALL)}
          >
            {t("recipes.form.allSubcategories")}
          </button>
          {INGREDIENT_CATEGORY_SUBCATEGORIES[category].map((s) => (
            <button
              key={s}
              type="button"
              className={`ingredient-picker__subcategory${subcategory === s ? " active" : ""}`}
              onClick={() => setSubcategory(s)}
            >
              <SubcategoryIcon subcategory={s} />
              {t(`recipes.form.subcategory.${s}`)}
            </button>
          ))}
        </div>
      )}

      {visible.length === 0 ? (
        <div className="ingredient-picker__empty">
          <p>{t("recipes.form.noIngredientFound")}</p>
          {onAddPlaceholder && trimmedQuery.length > 0 && (
            <button
              type="button"
              className="ingredient-picker__add-placeholder"
              onClick={handleAddPlaceholder}
            >
              {t("recipes.form.addPlaceholderButton", { name: trimmedQuery })}
            </button>
          )}
        </div>
      ) : (
        <div className="ingredient-picker__grid">
          {visible.map((ingredient) => (
            <button
              key={ingredient.id}
              type="button"
              className="ingredient-picker__card"
              onClick={() => handleSelect(ingredient)}
            >
              <span className="ingredient-picker__card-icon" aria-hidden="true">
                <IngredientTypeIcon icon={ingredient.icon} />
              </span>
              <span className="ingredient-picker__card-name">{ingredientLabel(ingredient, t)}</span>
              {showAllergens && <AllergenBadges allergens={ingredient.allergens} />}
              {showDiets && <DietBadges diets={ingredient.diets} />}
              {showReproducible && <ReproducibleBadge reproducible={ingredient.reproducible} />}
            </button>
          ))}
        </div>
      )}
    </div>
  );
}
