import { PrismaClient, RecipeOrigin } from "@prisma/client";
import { hashPassword } from "../src/shared/auth/password";
import { classifyRecipeDifficulty } from "../src/modules/recipes/application/services/recipeDifficulty";
import { RECIPE_TAG_DEFINITIONS } from "../src/modules/recipes/application/services/recipeTags";
import { buildStructuredIngredients } from "../src/modules/recipes/application/services/recipeIngredientParser";

const prisma = new PrismaClient();

const DEMO_PASSWORD = "chefdemo123";

const demoUsers = [
  {
    email: "chef.ava@example.com",
    username: "ava.stone",
    displayName: "Ava Stone",
    preferredLanguage: "en",
    dietaryPreferences: ["Mediterranean", "Quick meals"],
    dietaryRestrictions: [],
  },
  {
    email: "chef.luca@example.com",
    username: "luca.moretti",
    displayName: "Luca Moretti",
    preferredLanguage: "en",
    dietaryPreferences: ["High protein", "Mediterranean"],
    dietaryRestrictions: [],
  },
  {
    email: "chef.maya@example.com",
    username: "maya.chen",
    displayName: "Maya Chen",
    preferredLanguage: "en",
    dietaryPreferences: ["Quick meals", "Low carb"],
    dietaryRestrictions: ["Nut-free"],
  },
  {
    email: "chef.nora@example.com",
    username: "nora.silva",
    displayName: "Nora Silva",
    preferredLanguage: "en",
    dietaryPreferences: ["Vegetarian", "Quick meals"],
    dietaryRestrictions: ["Egg-free"],
  },
] as const;

const mealTypes = [
  ["breakfast", "Breakfast"],
  ["lunch", "Lunch"],
  ["dinner", "Dinner"],
  ["brunch", "Brunch"],
  ["snack", "Snack"],
] as const;

const cuisines = [
  ["mediterranean", "Mediterranean"],
  ["italian", "Italian"],
  ["asian", "Asian"],
  ["barbecue", "Barbecue"],
  ["seafood", "Seafood"],
  ["french", "French"],
] as const;

const imagePool = [
  "https://images.unsplash.com/photo-1544025162-d76694265947?auto=format&fit=crop&w=1200&q=80",
  "https://images.unsplash.com/photo-1519708227418-c8fd9a32b7a2?auto=format&fit=crop&w=1200&q=80",
  "https://images.unsplash.com/photo-1467003909585-2f8a72700288?auto=format&fit=crop&w=1200&q=80",
  "https://images.unsplash.com/photo-1482049016688-2d3e1b311543?auto=format&fit=crop&w=1200&q=80",
  "https://images.unsplash.com/photo-1504674900247-0877df9cc836?auto=format&fit=crop&w=1200&q=80",
  "https://images.unsplash.com/photo-1525351484163-7529414344d8?auto=format&fit=crop&w=1200&q=80",
  "https://images.unsplash.com/photo-1511690743698-d9d85f2fbf38?auto=format&fit=crop&w=1200&q=80",
  "https://images.unsplash.com/photo-1512058564366-18510be2db19?auto=format&fit=crop&w=1200&q=80",
  "https://images.unsplash.com/photo-1512621776951-a57141f2eefd?auto=format&fit=crop&w=1200&q=80",
  "https://images.unsplash.com/photo-1559847844-5315695dadae?auto=format&fit=crop&w=1200&q=80",
];

const recipeTemplates = [
  {
    title: "Lemon Herb Salmon Bowl",
    description:
      "Bright salmon with herbed grains, greens, and quick yogurt sauce.",
    mealTypeSlug: "dinner",
    cuisineSlug: "seafood",
    servings: 2,
    prepTimeMinutes: 15,
    cookTimeMinutes: 18,
    ingredients: [
      "2 salmon fillets",
      "1 cup cooked farro",
      "1 cucumber, sliced",
      "1 cup cherry tomatoes",
      "2 tbsp Greek yogurt",
      "1 lemon",
      "fresh dill",
    ],
    steps: [
      "Season the salmon with salt, pepper, and lemon zest.",
      "Roast or pan-sear the salmon until just cooked through.",
      "Build bowls with farro, cucumber, and tomatoes.",
      "Top with salmon and a spoonful of lemon yogurt.",
    ],
    tagSlugs: ["seafood", "quick", "mediterranean"],
  },
  {
    title: "Charred Steak and Sweet Potato Plate",
    description:
      "A hearty dinner with juicy steak, sweet potatoes, and greens.",
    mealTypeSlug: "dinner",
    cuisineSlug: "barbecue",
    servings: 2,
    prepTimeMinutes: 20,
    cookTimeMinutes: 22,
    ingredients: [
      "300 g flank steak",
      "2 sweet potatoes",
      "1 bunch broccolini",
      "olive oil",
      "smoked paprika",
      "garlic",
    ],
    steps: [
      "Roast the sweet potatoes until tender and caramelized.",
      "Season and sear the steak to your preferred doneness.",
      "Saute the broccolini with garlic and olive oil.",
      "Slice and plate everything with pan juices.",
    ],
    tagSlugs: ["comfort-food"],
  },
  {
    title: "Mushroom Ricotta Toasts",
    description:
      "Savory brunch toasts with ricotta, thyme, and sauteed mushrooms.",
    mealTypeSlug: "brunch",
    cuisineSlug: "italian",
    servings: 2,
    prepTimeMinutes: 10,
    cookTimeMinutes: 12,
    ingredients: [
      "4 slices sourdough",
      "1 cup ricotta",
      "250 g mushrooms",
      "1 garlic clove",
      "fresh thyme",
      "olive oil",
    ],
    steps: [
      "Toast the sourdough until crisp.",
      "Cook mushrooms with garlic, thyme, and olive oil.",
      "Spread ricotta on the toast.",
      "Pile mushrooms on top and finish with thyme.",
    ],
    tagSlugs: ["italian"],
  },
  {
    title: "Sesame Chicken Rice Bowl",
    description:
      "A balanced weeknight bowl with sesame chicken and crunchy greens.",
    mealTypeSlug: "lunch",
    cuisineSlug: "asian",
    servings: 2,
    prepTimeMinutes: 15,
    cookTimeMinutes: 16,
    ingredients: [
      "2 chicken thighs",
      "1 cup jasmine rice",
      "1 carrot, ribboned",
      "1 cup cabbage",
      "sesame oil",
      "soy sauce",
      "spring onion",
    ],
    steps: [
      "Cook the rice and set aside.",
      "Sear the chicken and glaze with soy and sesame oil.",
      "Toss the vegetables with a quick dressing.",
      "Assemble the bowl and garnish with spring onion.",
    ],
    tagSlugs: ["asian", "quick"],
  },
  {
    title: "Citrus Shrimp Couscous",
    description: "Quick shrimp with fluffy couscous, herbs, and citrus.",
    mealTypeSlug: "lunch",
    cuisineSlug: "mediterranean",
    servings: 2,
    prepTimeMinutes: 12,
    cookTimeMinutes: 10,
    ingredients: [
      "250 g shrimp",
      "1 cup couscous",
      "1 orange",
      "1 zucchini",
      "parsley",
      "olive oil",
    ],
    steps: [
      "Hydrate the couscous with hot stock or water.",
      "Saute the shrimp with olive oil and orange zest.",
      "Cook the zucchini until lightly golden.",
      "Fold everything together with parsley and citrus juice.",
    ],
    tagSlugs: ["seafood", "mediterranean", "quick"],
  },
  {
    title: "Green Shakshuka",
    description:
      "A fresh brunch skillet with greens, herbs, and gently baked eggs.",
    mealTypeSlug: "breakfast",
    cuisineSlug: "mediterranean",
    servings: 2,
    prepTimeMinutes: 14,
    cookTimeMinutes: 16,
    ingredients: [
      "4 eggs",
      "1 leek",
      "2 cups spinach",
      "1 cup peas",
      "fresh herbs",
      "feta",
    ],
    steps: [
      "Cook the leek until soft.",
      "Add greens and peas, then season well.",
      "Make wells and crack in the eggs.",
      "Cover until the eggs are just set and finish with feta.",
    ],
    tagSlugs: ["mediterranean", "comfort-food"],
  },
  {
    title: "Yogurt Berry Pancakes",
    description: "Fluffy pancakes with yogurt batter and warm berries.",
    mealTypeSlug: "breakfast",
    cuisineSlug: "french",
    servings: 3,
    prepTimeMinutes: 10,
    cookTimeMinutes: 14,
    ingredients: [
      "1 cup flour",
      "1 cup Greek yogurt",
      "2 eggs",
      "1 tsp baking powder",
      "mixed berries",
      "maple syrup",
    ],
    steps: [
      "Mix the batter until just combined.",
      "Cook pancakes on a lightly greased pan.",
      "Warm the berries in a small saucepan.",
      "Serve the pancakes with berries and maple syrup.",
    ],
    tagSlugs: ["sweet", "comfort-food"],
  },
  {
    title: "Tomato Basil Pasta",
    description:
      "Fast pasta with sweet tomatoes, basil, and plenty of olive oil.",
    mealTypeSlug: "dinner",
    cuisineSlug: "italian",
    servings: 2,
    prepTimeMinutes: 10,
    cookTimeMinutes: 15,
    ingredients: [
      "200 g pasta",
      "2 cups cherry tomatoes",
      "2 garlic cloves",
      "fresh basil",
      "parmesan",
      "olive oil",
    ],
    steps: [
      "Cook the pasta until al dente.",
      "Burst the tomatoes with garlic in olive oil.",
      "Toss the pasta with the tomato sauce.",
      "Finish with basil and parmesan.",
    ],
    tagSlugs: ["italian", "quick"],
  },
  {
    title: "Halloumi Grain Salad",
    description: "Warm halloumi with grains, roasted peppers, and herbs.",
    mealTypeSlug: "lunch",
    cuisineSlug: "mediterranean",
    servings: 2,
    prepTimeMinutes: 15,
    cookTimeMinutes: 12,
    ingredients: [
      "200 g halloumi",
      "1 cup cooked bulgur",
      "1 roasted red pepper",
      "mint",
      "parsley",
      "lemon",
    ],
    steps: [
      "Pan-fry the halloumi until golden.",
      "Mix bulgur with chopped pepper and herbs.",
      "Dress with lemon and olive oil.",
      "Top with warm halloumi and serve.",
    ],
    tagSlugs: ["mediterranean", "quick"],
  },
  {
    title: "Miso Glazed Cod",
    description: "Tender cod with miso glaze and quick greens.",
    mealTypeSlug: "dinner",
    cuisineSlug: "asian",
    servings: 2,
    prepTimeMinutes: 15,
    cookTimeMinutes: 16,
    ingredients: [
      "2 cod fillets",
      "1 tbsp miso paste",
      "1 tsp honey",
      "1 tsp soy sauce",
      "bok choy",
      "sesame seeds",
    ],
    steps: [
      "Mix miso, honey, and soy sauce.",
      "Brush the cod and bake until flaky.",
      "Saute the bok choy until just tender.",
      "Serve with sesame seeds on top.",
    ],
    tagSlugs: ["asian", "seafood"],
  },
];

function daysAgo(days: number) {
  const date = new Date();
  date.setDate(date.getDate() - days);
  return date;
}

function slugify(value: string) {
  return value
    .toLowerCase()
    .replace(/[^a-z0-9]+/g, "-")
    .replace(/^-+|-+$/g, "");
}

async function main() {
  for (const [slug, name] of cuisines) {
    await prisma.cuisine.upsert({
      where: { slug },
      update: { name },
      create: { slug, name },
    });
  }

  for (const [slug, name] of mealTypes) {
    await prisma.mealType.upsert({
      where: { slug },
      update: { name },
      create: { slug, name },
    });
  }

  for (const { slug, name } of RECIPE_TAG_DEFINITIONS) {
    await prisma.tag.upsert({
      where: { slug },
      update: { name },
      create: { slug, name },
    });
  }

  const demoPasswordHash = hashPassword(DEMO_PASSWORD);

  const users = await Promise.all(
    demoUsers.map(async (user) => {
      const saved = await prisma.user.upsert({
        where: { email: user.email },
        update: {
          username: user.username,
          displayName: user.displayName,
          preferredLanguage: user.preferredLanguage,
          passwordHash: demoPasswordHash,
        },
        create: {
          email: user.email,
          username: user.username,
          displayName: user.displayName,
          preferredLanguage: user.preferredLanguage,
          passwordHash: demoPasswordHash,
        },
      });

      await prisma.userPreference.upsert({
        where: { userId: saved.id },
        update: {
          dietaryPreferences: [...user.dietaryPreferences],
          dietaryRestrictions: [...user.dietaryRestrictions],
        },
        create: {
          userId: saved.id,
          dietaryPreferences: [...user.dietaryPreferences],
          dietaryRestrictions: [...user.dietaryRestrictions],
        },
      });

      return saved;
    }),
  );

  const userIds = users.map((user) => user.id);

  await prisma.favoriteRecipe.deleteMany({
    where: {
      OR: [
        { userId: { in: userIds } },
        { recipe: { userId: { in: userIds } } },
      ],
    },
  });

  await prisma.recipe.deleteMany({
    where: { userId: { in: userIds } },
  });

  await prisma.recipe.deleteMany({
    where: {
      shareSlug: {
        startsWith: "demo-",
      },
    },
  });

  const cuisineMap = Object.fromEntries(
    (await prisma.cuisine.findMany()).map((item) => [item.slug, item.id]),
  );
  const mealTypeMap = Object.fromEntries(
    (await prisma.mealType.findMany()).map((item) => [item.slug, item.id]),
  );
  const tagMap = Object.fromEntries(
    (await prisma.tag.findMany()).map((item) => [item.slug, item.id]),
  );

  const createdRecipes: Array<{ id: string; userId: string }> = [];

  for (const [userIndex, user] of users.entries()) {
    for (let i = 0; i < 10; i += 1) {
      const template =
        recipeTemplates[(userIndex * 3 + i) % recipeTemplates.length];
      const imageUrl = imagePool[(userIndex * 2 + i) % imagePool.length];
      const createdAt = daysAgo(userIndex * 3 + i);
      const displayName = user.displayName ?? "Chef";
      const title = `${displayName}'s ${template.title}`;
      const emailSlug = slugify(user.email.split("@")[0] ?? `chef-${userIndex + 1}`);
      const recipeSlug = slugify(template.title);

      const recipe = await prisma.recipe.create({
        data: {
          userId: user.id,
          cuisineId: cuisineMap[template.cuisineSlug] ?? null,
          mealTypeId: mealTypeMap[template.mealTypeSlug] ?? null,
          difficulty: classifyRecipeDifficulty({
            ingredients: template.ingredients,
            steps: template.steps,
            prepTimeMinutes: template.prepTimeMinutes,
            cookTimeMinutes: template.cookTimeMinutes,
            totalTimeMinutes: template.prepTimeMinutes + template.cookTimeMinutes,
          }).toUpperCase() as "EASY" | "MEDIUM" | "DIFFICULT",
          title,
          description: template.description,
          servings: template.servings,
          prepTimeMinutes: template.prepTimeMinutes,
          cookTimeMinutes: template.cookTimeMinutes,
          totalTimeMinutes: template.prepTimeMinutes + template.cookTimeMinutes,
          ingredients: template.ingredients,
          steps: template.steps,
          imageUrl,
          origin: RecipeOrigin.MANUAL,
          shareSlug: `demo-${emailSlug}-${i + 1}-${recipeSlug}`,
          createdAt,
          updatedAt: createdAt,
          recipeIngredients: {
            create: buildStructuredIngredients(template.ingredients).map(
              (ingredient, index) => ({
                originalText: ingredient.originalText,
                quantityText: ingredient.quantityText,
                amount: ingredient.amount,
                unit: ingredient.unit,
                preparation: ingredient.preparation,
                scalable: ingredient.scalable,
                position: ingredient.position ?? index,
              })
            ),
          },
          tags: {
            create: template.tagSlugs
              .map((tagSlug) => tagMap[tagSlug])
              .filter(Boolean)
              .map((tagId) => ({ tagId })),
          },
        },
      });

      createdRecipes.push({ id: recipe.id, userId: user.id });
    }
  }

  for (const user of users) {
    const foreignRecipes = createdRecipes
      .filter((recipe) => recipe.userId !== user.id)
      .slice(0, 8);

    for (const recipe of foreignRecipes) {
      await prisma.favoriteRecipe.upsert({
        where: {
          userId_recipeId: {
            userId: user.id,
            recipeId: recipe.id,
          },
        },
        update: {},
        create: {
          userId: user.id,
          recipeId: recipe.id,
        },
      });
    }
  }

  console.log("Demo seed complete.");
  console.log("Demo users:");
  for (const user of demoUsers) {
    console.log(`- ${user.email} / ${DEMO_PASSWORD}`);
  }
}

main()
  .catch((error) => {
    console.error("Seed failed:", error);
    process.exit(1);
  })
  .finally(async () => {
    await prisma.$disconnect();
  });
