import { parseQuantity } from "./parse-quantity";

const KNOWN_UNITS = new Set([
  "cup", "cups", "c",
  "tablespoon", "tablespoons", "tbsp", "tbsps", "tbs",
  "teaspoon", "teaspoons", "tsp", "tsps",
  "gram", "grams", "g",
  "kilogram", "kilograms", "kg",
  "ounce", "ounces", "oz",
  "pound", "pounds", "lb", "lbs",
  "milliliter", "milliliters", "millilitre", "millilitres", "ml",
  "liter", "liters", "litre", "litres", "l",
  "pinch", "pinches", "dash", "dashes",
  "clove", "cloves", "slice", "slices", "piece", "pieces", "pcs", "pc",
  "can", "cans", "jar", "jars", "package", "packages", "pkg",
  "bunch", "bunches", "sprig", "sprigs", "stick", "sticks",
  "quart", "quarts", "qt", "pint", "pints", "pt",
  "fl", // matches the first token of "fl oz" — handled below
  // French
  "tasse", "tasses", "cas", "cac", "gramme", "grammes", "kilogramme",
  "kilogrammes", "litre", "litres", "pincée", "pincees", "tranche", "tranches",
  "gousse", "gousses", "sachet", "sachets", "boîte", "boite", "boîtes", "boites",
  "morceau", "morceaux", "pièce", "pièces",
]);

// Leading numeric token: plain int/decimal, unicode fraction, mixed number ("1 1/2"), or
// simple fraction ("1/2") — mirrors what parseQuantity already knows how to parse.
const LEADING_NUMBER =
  /^\s*(\d+\s+\d+\s*\/\s*\d+|\d+\s*\/\s*\d+|\d+(?:\.\d+)?|[¼½¾⅓⅔⅕⅖⅗⅘⅙⅚⅛⅜⅝⅞])\s*/;

/**
 * Some AI-generated (or pasted/imported) ingredients arrive with the quantity baked into
 * the name itself (e.g. rawName: "2 cups flour"), sometimes ALONGSIDE an already-populated
 * quantity/unit pair (e.g. rawName: "1 avocat", quantity: "2", unit: "pcs" — the redundant
 * "1" was never stripped because an earlier version of this function only looked at
 * rawName when quantity/unit were both empty). This always strips a leading
 * quantity(+unit) token from the NAME when one is present, so the displayed ingredient is
 * just "avocat", never "1 avocat" — but only ever backfills the quantity/unit fields
 * themselves when they weren't already provided, so an existing explicit quantity/unit
 * (e.g. from summing across recipes) is never overwritten by whatever number happened to
 * be sitting in the name.
 */
export function extractIngredientQuantity(
  rawName: string,
  quantity: string | undefined,
  unit: string | undefined
): { rawName: string; quantity: string | undefined; unit: string | undefined } {
  const match = rawName.match(LEADING_NUMBER);
  if (!match) return { rawName, quantity, unit };

  const numberToken = match[1]!.trim();
  const parsedQuantity = parseQuantity(numberToken);
  if (parsedQuantity === undefined) return { rawName, quantity, unit };

  let rest = rawName.slice(match[0].length).trim();
  if (!rest) return { rawName, quantity, unit }; // nothing left — not actually a name+quantity string

  let strippedUnit: string | undefined;
  const unitMatch = rest.match(/^([a-zA-Z.]+)\s+(.*)$/);
  if (unitMatch) {
    const candidate = unitMatch[1]!.replace(/\.$/, "").toLowerCase();
    if (candidate === "fl" && unitMatch[2]!.toLowerCase().startsWith("oz")) {
      strippedUnit = "fl oz";
      rest = unitMatch[2]!.replace(/^oz\.?\s*/i, "").trim();
    } else if (KNOWN_UNITS.has(candidate)) {
      strippedUnit = candidate;
      rest = unitMatch[2]!.trim();
    }
  }

  if (!rest) return { rawName, quantity, unit }; // stripping the unit ate the whole string — bail out

  const hasExplicitQuantity = quantity !== undefined && quantity !== "";
  return {
    rawName: rest,
    quantity: hasExplicitQuantity ? quantity : parsedQuantity,
    unit: unit !== undefined && unit !== "" ? unit : strippedUnit,
  };
}
