import { describe, expect, it } from "vitest";
import { computeRecipeNutrition, type IngredientNutritionSource } from "@app/nutrition-engine";
import { SEED_INGREDIENTS } from "../src/seed/data/ingredients.js";
import { EXTRA_RECIPES } from "../src/seed/data/extra-recipes.js";
import { VERIFIED_RECIPES } from "../src/seed/data/verified-recipes.js";

/**
 * Rent invariant-test (ingen DB) för de nya extrarecepten. Speglar exakt de
 * kontroller som seed-körningen gör (run.ts rad 675 + 691) så att ett trasigt
 * recept fångas här i stället för mitt i en seed-körning:
 *  - varje ingrediens-id måste finnas i katalogen,
 *  - näringen måste gå att beräkna för varje ingrediens (rätt enhet),
 *  - inga slug-krockar med den befintliga katalogen.
 */

const byId = new Map(SEED_INGREDIENTS.map((i) => [i.id, i]));

function sourcesFor(
  recipe: (typeof EXTRA_RECIPES)[number],
): Map<string, IngredientNutritionSource> {
  const sources = new Map<string, IngredientNutritionSource>();
  for (const ri of recipe.ingredients) {
    const info = byId.get(ri.ing);
    if (!info) continue; // fångas separat av id-testet nedan
    sources.set(ri.ing, {
      nutritionPer100: info.nutritionPer100,
      densityGPerMl: info.densityGPerMl ?? null,
      gramsPerPiece: info.gramsPerPiece ?? null,
    });
  }
  return sources;
}

describe("extrarecept – seed-invarianter", () => {
  it("har minst 74 recept", () => {
    expect(EXTRA_RECIPES.length).toBeGreaterThanOrEqual(74);
  });

  it("alla ingrediens-id:n finns i katalogen (run.ts rad 675)", () => {
    const unknown: string[] = [];
    for (const recipe of EXTRA_RECIPES) {
      for (const ri of recipe.ingredients) {
        if (!byId.has(ri.ing)) unknown.push(`${recipe.slug}: ${ri.ing}`);
      }
    }
    expect(unknown).toEqual([]);
  });

  it("näringen går att beräkna för varje recept (run.ts rad 691)", () => {
    const failed: string[] = [];
    for (const recipe of EXTRA_RECIPES) {
      const calc = recipe.ingredients.map((ri) => ({
        canonicalIngredientId: ri.ing,
        quantity: ri.qty,
        unit: ri.unit,
        optional: ri.optional ?? false,
      }));
      const nutrition = computeRecipeNutrition(calc, recipe.portions, sourcesFor(recipe));
      if (nutrition.uncomputableIngredientIds.length > 0) {
        failed.push(`${recipe.slug}: ${nutrition.uncomputableIngredientIds.join(", ")}`);
      }
      // Rimlig näring per portion (fångar grova enhetsfel).
      expect(nutrition.perPortion.kcal).toBeGreaterThan(0);
    }
    expect(failed).toEqual([]);
  });

  it("inga slug-krockar med befintliga recept och inga interna dubbletter", () => {
    const existing = new Set(VERIFIED_RECIPES.map((r) => r.slug));
    const seen = new Set<string>();
    const collisions: string[] = [];
    for (const recipe of EXTRA_RECIPES) {
      if (existing.has(recipe.slug)) collisions.push(`krock: ${recipe.slug}`);
      if (seen.has(recipe.slug)) collisions.push(`dubblett: ${recipe.slug}`);
      seen.add(recipe.slug);
    }
    expect(collisions).toEqual([]);
  });

  it("varje bak-recept är taggat 'baking' (driver Baka-kategorin)", () => {
    const baking = EXTRA_RECIPES.filter((r) => r.tags.includes("baking"));
    expect(baking.length).toBeGreaterThanOrEqual(4);
  });
});
