import { resolveIngredientKey, type IngredientAliasIndex } from "./ingredient-match";

export const EXPIRING_WITHIN_DAYS = 3;

export function isExpiringSoon(expiresAt: Date | null): boolean {
  if (!expiresAt) return false;
  const days = Math.ceil((expiresAt.getTime() - Date.now()) / (1000 * 60 * 60 * 24));
  return days >= 0 && days <= EXPIRING_WITHIN_DAYS;
}

type ScorableRecipe<T> = T & { ingredients: { rawName: string }[] };

export function scoreRecipesAgainstPantry<T>(
  recipesList: ScorableRecipe<T>[],
  pantry: { rawName: string; expiresAt: Date | null }[],
  aliasIndex?: IngredientAliasIndex
) {
  // With no alias index, this resolves to a plain lowercase compare —
  // same behavior as before aliases existed.
  const keyOf = (name: string) => (aliasIndex ? resolveIngredientKey(name, aliasIndex) : name.trim().toLowerCase());

  const pantryKeys = new Set(pantry.map((p) => keyOf(p.rawName)));
  const expiringSoonKeys = new Set(
    pantry.filter((p) => isExpiringSoon(p.expiresAt)).map((p) => keyOf(p.rawName))
  );

  return recipesList
    .filter((r) => r.ingredients.length > 0)
    .map((recipe) => {
      const matched = recipe.ingredients.filter((ing) => pantryKeys.has(keyOf(ing.rawName))).length;
      const missing = recipe.ingredients
        .filter((ing) => !pantryKeys.has(keyOf(ing.rawName)))
        .map((ing) => ing.rawName)
        .slice(0, 5);
      const usesExpiring = recipe.ingredients
        .filter((ing) => expiringSoonKeys.has(keyOf(ing.rawName)))
        .map((ing) => ing.rawName);
      const total = recipe.ingredients.length;
      return { recipe, matched, total, pct: Math.round((matched / total) * 100), missing, usesExpiring };
    })
    .sort((a, b) => {
      if (a.usesExpiring.length > 0 !== b.usesExpiring.length > 0) {
        return a.usesExpiring.length > 0 ? -1 : 1;
      }
      return b.pct - a.pct;
    });
}
