import { createDatabase, closeDatabase } from "@app/database";
import { SEED_INGREDIENTS } from "@app/database/seed";
import * as fs from "node:fs/promises";
import * as path from "node:path";

const publicDir = "/mnt/c/Users/Public";

interface RecipeWithIngredients {
  id: string;
  slug: string;
  titleSv: string;
  titleEn: string | null;
  cuisine: string | null;
  mealType: string | null;
  dietVariant: string | null;
  sourceType: string;
  verificationStatus: string;
}

function normalizeDietVariant(raw: string | null): string {
  return raw ?? "standard";
}

async function main() {
  const dbUrl = process.env.DATABASE_URL;
  if (!dbUrl) throw new Error("DATABASE_URL saknas");
  const { db } = createDatabase(dbUrl);

  const recipes = (await db.query.recipes.findMany({
    where: (t, { inArray }) => inArray(t.verificationStatus, ["verified", "editorial"]),
  })) as RecipeWithIngredients[];

  const enriched = [];
  for (const r of recipes) {
    const ingredients = await db.query.recipeIngredients.findMany({
      where: (t, { eq }) => eq(t.recipeId, r.id),
    });
    const steps = await db.query.recipeSteps.findMany({
      where: (t, { eq }) => eq(t.recipeId, r.id),
    });
    enriched.push({ ...r, ingredients, steps });
  }

  // ── Coverage matrix ──────────────────────────────────────────────────────
  const mainIds = Array.from(new Set(SEED_INGREDIENTS.map((i) => i.id)));
  const matrix = new Map<string, Map<string, number>>();

  for (const r of recipes) {
    const ingredients = await db.query.recipeIngredients.findMany({
      where: (t, { eq }) => eq(t.recipeId, r.id),
    });
    const mainIngs = ingredients.filter((ing) => mainIds.includes(ing.canonicalIngredientId));
    const diet = normalizeDietVariant(r.dietVariant);
    for (const ing of mainIngs) {
      if (!matrix.has(ing.canonicalIngredientId)) matrix.set(ing.canonicalIngredientId, new Map());
      const cell = matrix.get(ing.canonicalIngredientId)!;
      cell.set(diet, (cell.get(diet) ?? 0) + 1);
    }
  }

  const coverageMatrix = mainIds.map((id) => {
    const ing = SEED_INGREDIENTS.find((i) => i.id === id);
    const cell = matrix.get(id) ?? new Map<string, number>();
    return {
      ingredientId: id,
      nameSv: ing?.nameSv ?? id,
      category: ing?.category ?? "unknown",
      total: Array.from(cell.values()).reduce((s, v) => s + v, 0),
      byDiet: Object.fromEntries(cell),
    };
  }).sort((a, b) => a.total - b.total);

  const thinCells = coverageMatrix.filter((c) => c.total <= 2);

  // ── Dedup / similarity stats ─────────────────────────────────────────────
  const slugs = recipes.map((r) => r.slug);
  const uniqueSlugs = new Set(slugs);
  const titleWords = recipes.map((r) =>
    r.titleSv.toLowerCase().replace(/[^\w\s]/g, "").split(/\s+/).filter((w) => w.length > 3),
  );
  const titleSignatures = titleWords.map((words) => words.slice(0, 4).sort().join(" "));
  const sigCounts = new Map<string, number>();
  for (const sig of titleSignatures) sigCounts.set(sig, (sigCounts.get(sig) ?? 0) + 1);
  const suspectedDupes = Array.from(sigCounts.entries()).filter(([, n]) => n > 1);

  // ── Cost summary ─────────────────────────────────────────────────────────
  // Round 1 from earlier log summary; round 2 from the combined logs below.
  const round1CostUsd = 0.0612;
  const round2CostUsd = 0.0546; // g1 0.0040 + g2 0.0169 + g3 0.0337
  const totalCostUsd = round1CostUsd + round2CostUsd;

  const summary = {
    exportedAt: new Date().toISOString(),
    totalVerified: recipes.length,
    editorialRecipes: recipes.filter((r) => r.sourceType === "own_editorial").length,
    aiAssistedRecipes: recipes.filter((r) => r.sourceType === "ai_assisted_reviewed").length,
    editorialRecipesByStatus: recipes.filter((r) => r.verificationStatus === "editorial").length,
    verifiedRecipesByStatus: recipes.filter((r) => r.verificationStatus === "verified").length,
    dedupStats: {
      totalSlugs: slugs.length,
      uniqueSlugs: uniqueSlugs.size,
      duplicateSlugs: slugs.length - uniqueSlugs.size,
      suspectedTitleSignatureDuplicates: suspectedDupes.length,
      suspectedTitleSignatures: suspectedDupes.map(([sig, n]) => ({ signature: sig, count: n })),
    },
    coverageStats: {
      totalCanonicalIngredients: mainIds.length,
      ingredientsWithVerifiedRecipes: coverageMatrix.filter((c) => c.total > 0).length,
      thinCellsCount: thinCells.length,
      thinnestCells: thinCells.slice(0, 10),
    },
    costUsd: {
      round1: round1CostUsd,
      round2: round2CostUsd,
      total: totalCostUsd,
    },
  };

  await fs.writeFile(
    path.join(publicDir, "cibello-verified-final-result.json"),
    JSON.stringify({ exportedAt: new Date().toISOString(), count: enriched.length, recipes: enriched }, null, 2),
    "utf-8",
  );

  await fs.writeFile(
    path.join(publicDir, "cibello-verified-final-coverage-matrix.json"),
    JSON.stringify({ exportedAt: new Date().toISOString(), coverageMatrix }, null, 2),
    "utf-8",
  );

  await fs.writeFile(
    path.join(publicDir, "cibello-verified-final-dedup-stats.json"),
    JSON.stringify({ exportedAt: new Date().toISOString(), ...summary.dedupStats }, null, 2),
    "utf-8",
  );

  await fs.writeFile(
    path.join(publicDir, "cibello-verified-final-summary.md"),
    `# Cibello Receptkatalog – Final Verified Set

- **Exporterad:** ${summary.exportedAt}
- **Totalt godkända recept (verified + editorial):** ${summary.totalVerified}
  - Editorial: ${summary.editorialRecipes} (status=editorial)
  - AI-assisted & reviewed: ${summary.aiAssistedRecipes} (status=verified)
- **Kostnad:** $${summary.costUsd.total.toFixed(4)} (runda 1: $${summary.costUsd.round1.toFixed(4)}, runda 2: $${summary.costUsd.round2.toFixed(4)})

## Dedup-statistik

- Unika slugs: ${summary.dedupStats.uniqueSlugs} / ${summary.dedupStats.totalSlugs}
- Dublett-slugs: ${summary.dedupStats.duplicateSlugs}
- Misstänkta titel-signatur-dubbletter: ${summary.dedupStats.suspectedTitleSignatureDuplicates}

## Täckningsmatris (tunnaste cellerna)

| Huvudingrediens | Kategori | Totalt | Fördelning |
|---|---|---:|---|
${thinCells.slice(0, 15).map((c) => `| ${c.nameSv} | ${c.category} | ${c.total} | ${JSON.stringify(c.byDiet)} |`).join("\n")}

## Granskning

Setet är redo för allergen- + närings-sanity av granskare.
`,
    "utf-8",
  );

  console.error(`[export-verified] Exported ${recipes.length} verified recipes`);
  console.error(`  result.json        -> ${path.join(publicDir, "cibello-verified-final-result.json")}`);
  console.error(`  coverage-matrix    -> ${path.join(publicDir, "cibello-verified-final-coverage-matrix.json")}`);
  console.error(`  dedup-stats        -> ${path.join(publicDir, "cibello-verified-final-dedup-stats.json")}`);
  console.error(`  summary.md         -> ${path.join(publicDir, "cibello-verified-final-summary.md")}`);

  await closeDatabase();
}

main().catch((err) => { console.error(err); process.exit(1); });
