import type {
  AllergyView,
  DietView,
  IngredientView,
  TechStepView,
  UnitView,
  UtensilView,
} from "./reference.js";

/**
 * Who can *read* a recipe — mirrors `RecipeVisibility` in schema.prisma.
 * Declared by hand (not derived from `@prisma/client`) — same reasoning as
 * `AllergenKind`: `apps/web` never depends on the Prisma client. Controls
 * only visibility, never editing — a recipe can only ever be edited/deleted
 * by its author, whatever this is set to.
 */
export type RecipeVisibility = "PERSONAL" | "HOUSE" | "PUBLIC";

/**
 * One ingredient line within a recipe, as returned in {@link RecipeView} —
 * the ingredient resolved to its full reference data (name, icon,
 * allergens), plus the quantity specific to this recipe (carried by
 * `RecipeIngredient` in schema.prisma, not by `Ingredient` itself). `unit`
 * is likewise resolved to its full reference data (`Unit`) rather than a
 * raw key — same "resolve at read time" treatment as `ingredient`, now that
 * it's a catalog reference instead of free text (see `UnitView`).
 */
export interface RecipeIngredientView {
  ingredient: IngredientView;
  quantity: number;
  unit: UnitView;
}

/**
 * One detected technique within a {@link StepView}'s description, resolved
 * to its reference data (same "resolve at read time" treatment as
 * {@link RecipeIngredientView}'s `ingredient`/`unit`) alongside exactly
 * where in `description` it was matched — two nested `[start, end)` spans
 * (same convention as `String.prototype.slice`), what the recipe detail
 * view highlights:
 *
 * - `start`/`end` — the tight *keyword* span (e.g. "préchauffer"),
 *   highlighted strongly with a tooltip naming the technique
 *   (`techStep.key` resolves the label through `catalog.techSteps.<key>`
 *   i18n, the same pattern as every other reference catalog).
 * - `contextStart`/`contextEnd` — the wider surrounding *clause* the
 *   keyword was found in (e.g. "Dans une poêle chaude" for a `preheat`
 *   keyword of "poêle chaude"), highlighted more subtly around it.
 *   Optional: absent on a match made before this pair of columns existed
 *   and not yet recomputed (see `StepTechStep`'s schema doc comment) — a
 *   caller with no context just shows the keyword highlight alone, same as
 *   before these existed.
 *
 * `source` mirrors `StepTechStep.source` (schema.prisma) — `"auto"` is the
 * classifier's own detection, `"manual"` is a viewer's correction applied
 * immediately (`recipe-tech-step-correction.service.ts`'s
 * `applyManualCorrection`). `StepDescription.tsx` renders the two with a
 * different highlight color so a viewer can tell which is which.
 *
 * `ingredients`/`utensils` are the metadata found in this technique's own
 * clause (see `tech-step-matcher.ts`'s `TechStepMatch` — same source data,
 * just resolved to full reference views here instead of bare ids) — `[]`
 * when nothing was mentioned alongside this technique.
 */
export interface StepTechStepView {
  techStep: TechStepView;
  start: number;
  end: number;
  contextStart?: number;
  contextEnd?: number;
  source: "auto" | "manual";
  ingredients: StepTechStepIngredientView[];
  utensils: StepTechStepUtensilView[];
}

/**
 * An ingredient mentioned in the same clause as a detected technique (see
 * {@link StepTechStepView.ingredients}) — `quantity`/`unit` are `null` when
 * none was recognized immediately before the mention (e.g. "ajouter le
 * sel"), same "best-effort, not always present" contract as
 * `tech-step-matcher.ts`'s `IngredientMention`. `start`/`end` are the
 * mention's own span in the step's `description`, same `[start, end)`
 * convention as {@link StepTechStepView.start}.
 *
 * `source` mirrors {@link StepTechStepView.source} — `"auto"` is the
 * classifier's own detection, `"manual"` is a viewer's own selection
 * (`SubmitTechStepCorrectionInput.ingredients`, `TechStepCorrectionPopover.tsx`).
 */
export interface StepTechStepIngredientView {
  ingredient: IngredientView;
  quantity: number | null;
  unit: UnitView | null;
  start: number;
  end: number;
  source: "auto" | "manual";
}

/** A utensil mentioned in the same clause as a detected technique (see {@link StepTechStepView.utensils}) — `source` mirrors {@link StepTechStepIngredientView.source}. */
export interface StepTechStepUtensilView {
  utensil: UtensilView;
  start: number;
  end: number;
  source: "auto" | "manual";
}

/**
 * A single preparation step within a recipe, in `order`. `techSteps` is its
 * detected technique sequence (`Step.techSteps`/`StepTechStep` in
 * schema.prisma, auto-computed at save time via `tech-step-matcher.ts`) —
 * empty if the description doesn't mention any known technique, or if it
 * does but the match predates `StepTechStep.start`/`end` existing and the
 * recipe hasn't been resaved since (see the schema doc comment).
 */
export interface StepView {
  id: number;
  description: string;
  picture: string | null;
  order: number;
  techSteps: StepTechStepView[];
}

/**
 * A recipe as it appears in the catalog table (`GET /recipes`) — enough to
 * render a row without fetching every recipe's full detail. `allergens` is
 * the union of every ingredient's allergens, deduplicated by allergy id —
 * the same aggregation `GET /recipes/:id` performs for {@link RecipeView},
 * kept consistent so the table's badges match the detail panel's.
 *
 * `isFavorite` and `diets` are resolved for the *requesting* user/recipe —
 * `isFavorite` is per-viewer (see `RecipeFavorite` in schema.prisma), while
 * `diets` is a property of the recipe itself (manually tagged by its
 * author, not viewer-specific).
 */
export interface RecipeSummaryView {
  id: number;
  name: string;
  description: string | null;
  picture: string | null;
  /** How many portions this recipe yields as written. Surfaced on the summary (not just the full detail) so the planning recipe picker can pre-fill its own "how many portions?" step from it — see `RecipePickerDialog`. */
  portions: number;
  authorId: number;
  visibility: RecipeVisibility;
  allergens: AllergyView[];
  diets: DietView[];
  isFavorite: boolean;
}

/** Full recipe detail, as returned by `GET /recipes/:id`. */
export interface RecipeView extends RecipeSummaryView {
  ingredients: RecipeIngredientView[];
  steps: StepView[];
}

/**
 * One user-submitted correction to a step's detected techniques, as
 * returned by `GET /recipes/:id/steps/:stepId/corrections` — the read side
 * of `POST` on the same route (`submitTechStepCorrectionSchema`,
 * `packages/shared/src/schemas/recipe.ts`). `previousTechStep`/
 * `correctedTechStep` are resolved to their reference data (same "resolve
 * at read time" treatment as {@link StepTechStepView.techStep}) rather than
 * bare ids — `null` carries the same "missing"/"none" meaning documented on
 * `StepTechStepCorrection` in schema.prisma. Not shown to *every* viewer of
 * a step by default in `apps/web` today (see `StepDescription.tsx`) —
 * mainly useful for a user checking what they (or others) already
 * submitted before adding another correction to the same span.
 */
export interface StepTechStepCorrectionView {
  id: number;
  start: number;
  end: number;
  previousTechStep: TechStepView | null;
  correctedTechStep: TechStepView | null;
  createdAt: string;
}

/**
 * Response of `POST /recipes/:id/steps/:stepId/corrections` — the audit
 * record just created, plus the step's fresh, immediately up-to-date
 * `techSteps` sequence (`StepView.techSteps`'s own shape) after applying
 * it. `apps/web`'s `StepDescription.tsx` replaces its local copy of the
 * step's `techSteps` with this on a successful submit, so the new/relabeled
 * `"manual"`-sourced highlight appears right away — the API is the single
 * source of truth for exactly which entry changed and how (a relabel
 * updates one row in place, an add inserts one, a remove deletes one; see
 * `recipe-tech-step-correction.service.ts`'s `applyManualCorrection`), so
 * the frontend never tries to replicate that logic client-side.
 */
export interface SubmitTechStepCorrectionResult {
  correction: StepTechStepCorrectionView;
  techSteps: StepTechStepView[];
}
