/**
 * A dietary regime, as returned by `GET /reference/diets` — reference data
 * (`Diet`, seeded via `apps/api/prisma/seed.ts`), not user-specific.
 *
 * `key` is a stable, English camelCase uid (e.g. `"vegetarian"`), not a
 * display label — it never changes once seeded, unlike the label it stands
 * in for. Callers resolve the label themselves via i18n
 * (`t(\`catalog.diets.${key}\`)`, `apps/web`'s `locales/fr/translation.json`),
 * the same way `IngredientCategory`/`IngredientSubcategory` enum values
 * already do (see `recipes.form.category.*`/`recipes.form.subcategory.*` in
 * that file).
 */
export interface DietView {
  id: number;
  key: string;
}

/**
 * Whether an allergen is a true (IgE-mediated) allergy or a non-immune
 * intolerance — mirrors `AllergenKind` in `schema.prisma`. Declared by hand
 * here rather than derived from the Prisma enum, same reasoning as
 * `SafeUserProfile`: `apps/web` must not depend on `@prisma/client`.
 */
export type AllergenKind = "ALLERGY" | "INTOLERANCE";

/**
 * A selectable allergen, as returned by `GET /reference/allergies`.
 *
 * `key` is resolved server-side from the parent `Category` — the `Allergy`
 * table itself carries no key of its own (see `schema.prisma`), so this
 * flattens that split away: callers just get `{id, key}` and never need to
 * know a `Category` exists underneath. Like {@link DietView.key}, it's a
 * stable English camelCase uid (e.g. `"gluten"`), not a display label —
 * resolved via `t(\`catalog.allergens.${key}\`)`. `kind` groups allergens
 * into two separate lists client-side (`AllergySelect`, `apps/web`) rather
 * than one flat "allergies & intolerances" list — a single
 * `PATCH /profile/allergies` call still covers both, this is a display
 * grouping only.
 */
export interface AllergyView {
  id: number;
  key: string;
  kind: AllergenKind;
}

/**
 * Supermarket-aisle grouping ("rayons") — mirrors `IngredientCategory` in
 * schema.prisma, declared by hand for the same reason as
 * {@link AllergenKind}. Lets the ingredient picker (`apps/web`'s
 * `IngredientPicker`) offer category browsing, not just free-text search:
 * with 400+ reference ingredients, search alone doesn't scale to actually
 * *finding* one. See {@link INGREDIENT_SUBCATEGORIES} for the finer-grained
 * rack within each aisle.
 */
export const INGREDIENT_CATEGORIES = [
  "freshProduce",
  "meatAndSeafood",
  "dryGoods",
  "bakery",
  "dairyAndCheese",
  "condimentsAndSpices",
  "cookingEssentials",
] as const;
/** Inferred TS type for one {@link INGREDIENT_CATEGORIES} member. */
export type IngredientCategory = (typeof INGREDIENT_CATEGORIES)[number];

/**
 * Finer-grained rack within one {@link IngredientCategory} aisle — mirrors
 * `IngredientSubcategory` in schema.prisma. See
 * {@link INGREDIENT_CATEGORY_SUBCATEGORIES} for which of these belongs to
 * which category, and in what display order.
 */
export const INGREDIENT_SUBCATEGORIES = [
  "vegetables",
  "fruits",
  "freshHerbs",
  "meats",
  "poultry",
  "fish",
  "shellfish",
  "starches",
  "legumes",
  "nutsAndSeeds",
  "other",
  "breads",
  "rawDough",
  "dairy",
  "eggs",
  "plantBasedAlternatives",
  "spices",
  "sauces",
  "seasonings",
  "bases",
  "thickeners",
  "sugars",
] as const;
/** Inferred TS type for one {@link INGREDIENT_SUBCATEGORIES} member. */
export type IngredientSubcategory = (typeof INGREDIENT_SUBCATEGORIES)[number];

/**
 * Which {@link INGREDIENT_SUBCATEGORIES} belong to which
 * {@link INGREDIENT_CATEGORIES} aisle, in the order the picker should list
 * them — the two-level drill-down `IngredientPicker` (`apps/web`) needs
 * this to know which subcategory chips to offer once a category is picked.
 * Mirrors `apps/api/src/db/reference-seed-data.ts`'s `INGREDIENT_GROUPS`,
 * which is the actual source of truth for which *ingredient* belongs to
 * which pair — this is just the category→subcategory shape of that data,
 * duplicated here since the seed file isn't reachable from `apps/web`.
 */
export const INGREDIENT_CATEGORY_SUBCATEGORIES: Record<
  IngredientCategory,
  readonly IngredientSubcategory[]
> = {
  freshProduce: ["vegetables", "fruits", "freshHerbs"],
  meatAndSeafood: ["meats", "poultry", "fish", "shellfish"],
  dryGoods: ["starches", "legumes", "nutsAndSeeds", "other"],
  bakery: ["breads", "rawDough"],
  dairyAndCheese: ["dairy", "eggs", "plantBasedAlternatives"],
  condimentsAndSpices: ["spices", "sauces", "seasonings"],
  cookingEssentials: ["bases", "thickeners", "sugars"],
};

/**
 * Generic pictogram *type* for an ingredient — mirrors `IngredientIcon` in
 * schema.prisma, declared by hand for the same reason as
 * {@link AllergenKind}. Was a free-text emoji per ingredient (437 distinct
 * characters); replaced with this small, shared vocabulary of ~20 generic
 * shapes ("a vegetable", "a bottle", "a wedge of cheese"…) so
 * `apps/web`'s `features/recipes/ingredient-icons.tsx` can render a real
 * SVG line icon per ingredient instead — see that file for the actual
 * pictograms and the full reasoning.
 */
export const INGREDIENT_ICONS = [
  "VEGETABLE",
  "FRUIT",
  "HERB",
  "MEAT",
  "POULTRY",
  "FISH",
  "SHELLFISH",
  "GRAIN",
  "LEGUME",
  "NUT_SEED",
  "BREAD",
  "DOUGH",
  "MILK",
  "CHEESE",
  "EGG",
  "SPROUT",
  "SPICE",
  "JAR",
  "BOTTLE",
  "DRINK",
  "STOCK_POT",
  "SUGAR",
] as const;
/** Inferred TS type for one {@link INGREDIENT_ICONS} member. */
export type IngredientIcon = (typeof INGREDIENT_ICONS)[number];

/**
 * Which physical quantity a {@link UnitView} measures — mirrors `UnitType`
 * in schema.prisma, declared by hand for the same reason as
 * {@link AllergenKind}. Only units of the same type are ever mutually
 * convertible via `toBaseFactor` — see {@link UnitView}.
 */
export type UnitType = "MASS" | "VOLUME" | "COUNT";

/**
 * A recipe ingredient unit, as returned by `GET /reference/units` —
 * reference data (`Unit`, seeded via `reference-seed-data.ts`'s `UNITS`),
 * same static/non-administrable status as {@link DietView}/
 * {@link AllergyView}.
 *
 * `key` is a stable English camelCase uid (e.g. `"tablespoon"`), not a
 * display label — resolved via `t(\`catalog.units.${key}\`)`, same as
 * {@link DietView.key}. `toBaseFactor` is how many of `type`'s base unit
 * (gram for MASS, milliliter for VOLUME, itself for COUNT) one of this unit
 * equals — groundwork for a future conversion feature (e.g. a shopping list
 * summing "500g" + "0.5kg" into "1kg"), not that feature itself: COUNT
 * units all carry `toBaseFactor: 1` and don't convert to one another (a
 * "pincée" isn't a fixed fraction of a "gousse").
 */
export interface UnitView {
  id: number;
  key: string;
  type: UnitType;
  toBaseFactor: number;
}

/**
 * A cooking technique, as returned by `GET /reference/tech-steps` —
 * reference data (`TechStep`, seeded via `reference-seed-data.ts`'s
 * `TECH_STEPS`), same static/non-administrable status as
 * {@link DietView}/{@link UnitView}.
 *
 * Not currently surfaced in the recipe UI — a step's technique sequence
 * (`Step.techSteps`/`StepTechStep` in schema.prisma) is computed
 * server-side at save time (see `recipe.service.ts`'s `createRecipe`/
 * `updateRecipe`, via `tech-step-matcher.ts`'s `matchTechSteps`) but
 * deliberately excluded from `StepView` (see its doc comment in
 * `types/recipe.ts`). This endpoint exists for consistency with the other
 * reference catalogs and for future admin/inspection tooling.
 *
 * `key` is a stable English camelCase uid (e.g. `"simmer"`), not a display
 * label — resolved via `t(\`catalog.techSteps.${key}\`)`, same as
 * {@link DietView.key}.
 */
export interface TechStepView {
  id: number;
  key: string;
}

/**
 * A cooking utensil, as returned by `GET /reference/utensils` — reference
 * data (`Utensil`, seeded via `reference-seed-data.ts`'s `UTENSILS`), same
 * bare `id`+`key` shape and static/non-administrable status as
 * {@link TechStepView}. Detected in a step's free text the same way
 * techniques are (see `StepTechStepUtensilView`), but via a static
 * `PhraseMatcher` rather than a trained classifier — see
 * `services/tech-step-intent-service`'s `utensil_vocabulary.py`.
 *
 * `key` is a stable English camelCase uid (e.g. `"pan"`), not a display
 * label — resolved via `t(\`catalog.utensils.${key}\`)`, same as
 * {@link TechStepView.key}.
 */
export interface UtensilView {
  id: number;
  key: string;
}

/**
 * An implemented recipe source, as returned by `GET /reference/sources` —
 * reference data (`Source`, kept in sync with the adapter registry by
 * `syncRecipeSources`, `apps/api/src/db/recipe-source-sync.ts`), same
 * static/non-administrable status as {@link DietView}/{@link UnitView} from
 * a client's point of view (nothing here is ever created/edited through
 * the API — only a real adapter being registered in code adds a row).
 *
 * Unlike `DietView`/`TechStepView`, `name` is the actual display string
 * (e.g. `"TheMealDB"`) rather than a `key` resolved through
 * `catalog.<domain>.<key>` — a source's name is a proper noun/brand,
 * nothing to translate. `official` distinguishes a source backed by an
 * official API from one built by scraping HTML the site never committed to
 * a stable shape — surfaced so households can make an informed choice when
 * picking which sources to enable (see `HouseSource` in schema.prisma).
 * `iconUrl` is the source's own logo/favicon, `null` if it has none worth
 * showing — `SourceSelect` (apps/web) renders it next to `name`.
 */
export interface SourceView {
  id: number;
  key: string;
  name: string;
  official: boolean;
  iconUrl: string | null;
}

/**
 * A selectable ingredient, as returned by `GET /reference/ingredients` —
 * reference data (`Ingredient`, seeded via `apps/api/src/db/
 * reference-seed-data.ts`), same "static, non-administrable" status as
 * {@link DietView}/{@link AllergyView}: no create/update/delete endpoint
 * exists for it, only the seed populates it.
 *
 * `allergens` is resolved server-side from the `IngredientAllergy` join
 * table — empty for an ingredient that carries none of the 14 EU-regulated
 * allergens. `diets` is resolved from `IngredientDiet` the same way — the
 * regimes this ingredient is compatible with (e.g. `vegetarian`, `vegan`),
 * so the picker can flag it without the user opening its packaging. Omits
 * `omnivore` (every ingredient qualifies, so it's never stored) and
 * `glutenFree` (already derivable from whether `allergens` contains
 * `gluten` — see `IngredientDiet` in schema.prisma). Used by the recipe
 * catalog (`apps/web`'s recipe form and detail page) to pick ingredients and
 * to surface which allergens/regimes a recipe contains, aggregated across
 * its ingredients.
 *
 * `key` is a stable English camelCase uid (e.g. `"tomato"`), not a display
 * label — like {@link DietView.key}, resolved via
 * `t(\`catalog.ingredients.${key}\`)` — **except** for a placeholder (see
 * `isPlaceholder`), whose label is `displayName` verbatim. Consumers must
 * therefore resolve the label as `displayName ?? t(\`catalog.ingredients.${key}\`)`
 * (helper: `apps/web`'s `features/recipes/ingredients/ingredient-label.ts`).
 */
export interface IngredientView {
  id: number;
  key: string;
  icon: IngredientIcon;
  category: IngredientCategory;
  subcategory: IngredientSubcategory;
  /** Whether this ingredient is reasonably makeable at home (a burger bun, a béchamel) rather than something you'd only ever buy — see `Ingredient.reproducible` in schema.prisma. Surfaced as a badge/link in the recipe form nudging toward the recipe catalog's own search, not a link to a specific recipe. */
  reproducible: boolean;
  allergens: AllergyView[];
  diets: DietView[];
  /**
   * `true` = a free-text ingredient a user typed on a recipe line because
   * the catalog had nothing matching — see `Ingredient.isPlaceholder` in
   * schema.prisma. Never returned by `GET /reference/ingredients` (the
   * browsable catalog excludes them); only ever seen inside a recipe's own
   * ingredient list. Rendered with an "à compléter" badge and no
   * allergen/diet info.
   */
  isPlaceholder: boolean;
  /** The user-typed name when `isPlaceholder` — `null` for a real catalog ingredient (its label is in i18n). */
  displayName: string | null;
}
