import type { Substitution, Unit } from "@app/shared-types";

export interface SubstitutableIngredient {
  canonicalIngredientId: string;
  displayNameSv: string;
  quantity: number;
  unit: Unit;
  optional: boolean;
}

export interface SubstitutionResult {
  ingredients: SubstitutableIngredient[];
  applied: {
    fromId: string;
    toId: string;
    ratio: number;
    instructionsSv?: string | undefined;
    warningSv?: string | undefined;
  };
}

/**
 * Substitutionsmotor (spec §20): byt ingrediens med mängdfaktor och
 * instruktionspåverkan. Näringen räknas ALLTID om av nutrition-engine efteråt –
 * denna modul ändrar bara ingredienslistan.
 */
export function applySubstitution(
  ingredients: SubstitutableIngredient[],
  substitution: Pick<
    Substitution,
    "fromIngredientId" | "toIngredientId" | "ratio" | "instructionsSv" | "notRecommendedFor"
  >,
  toDisplayNameSv: string,
  context?: string,
): SubstitutionResult {
  const target = ingredients.find((i) => i.canonicalIngredientId === substitution.fromIngredientId);
  if (!target) {
    throw new Error(
      `Ingrediensen ${substitution.fromIngredientId} finns inte i receptet och kan inte bytas.`,
    );
  }

  let warningSv: string | undefined;
  if (context && substitution.notRecommendedFor.includes(context)) {
    warningSv = `Observera: detta byte rekommenderas inte för ${context}.`;
  }

  const next = ingredients.map((ing) =>
    ing.canonicalIngredientId === substitution.fromIngredientId
      ? {
          ...ing,
          canonicalIngredientId: substitution.toIngredientId,
          displayNameSv: toDisplayNameSv,
          quantity: Math.round(ing.quantity * substitution.ratio * 100) / 100,
        }
      : ing,
  );

  return {
    ingredients: next,
    applied: {
      fromId: substitution.fromIngredientId,
      toId: substitution.toIngredientId,
      ratio: substitution.ratio,
      instructionsSv: substitution.instructionsSv ?? undefined,
      warningSv,
    },
  };
}
