// @WHO:   vps-deploy/api/kds/src/routes/recipe.ts
// @WHAT:  Recipe CRUD routes — link Menu ↔ Ingredient for stock deduction
// @PART:  api
// @ENTRY: recipeRouter

import { Router } from 'express';
import { prisma } from '../lib/prisma';
import { authMiddleware } from '../middleware/auth';

export const recipeRouter = Router();

// All recipe routes require auth
recipeRouter.use(authMiddleware);

// ── Recipe CRUD ──

// @FLOW:     RECIPE_LIST
// @CALLS:    DB:recipes SELECT (include ingredient)
// @MUTATES:  none
recipeRouter.get('/outlets/:id/menus/:menuId/recipes', async (req, res) => {
  try {
    const { id: outletId, menuId } = req.params;

    // Verify menu belongs to this outlet
    const menu = await prisma.menu.findFirst({
      where: { id: menuId, outletId },
    });

    if (!menu) {
      return res.status(404).json({ error: 'Menu not found in this outlet' });
    }

    const recipes = await prisma.recipe.findMany({
      where: { menuId },
      include: {
        ingredient: { select: { id: true, name: true, unit: true, costPerUnit: true, yieldPercent: true } },
      },
      orderBy: { ingredient: { name: 'asc' } },
    });

    res.json(recipes);
  } catch (err: any) {
    res.status(500).json({ error: 'Failed to fetch recipes', message: err.message });
  }
});

// @FLOW:     RECIPE_REPLACE_ALL
// @CALLS:    DB:recipes DELETE (by menuId), DB:recipes INSERT (many)
// @MUTATES:  DB:recipes (DELETE + INSERT in transaction)
// @BEHAVIOR: Accepts full recipe array, atomically replaces all recipes for a menu.
//            Frontend sends the complete recipe list; backend deletes existing and creates new.
recipeRouter.post('/outlets/:id/menus/:menuId/recipes', async (req, res) => {
  try {
    const { id: outletId, menuId } = req.params;
    const items: Array<{
      ingredientId: string;
      quantity: number;
      prepQuantity?: number;
      isOptional?: boolean;
      prepInstruction?: string;
    }> = req.body;

    if (!Array.isArray(items)) {
      return res.status(400).json({ error: 'Request body must be an array of recipe items' });
    }

    // Validate each item
    for (let i = 0; i < items.length; i++) {
      const item = items[i];
      if (!item.ingredientId || item.quantity === undefined || item.quantity <= 0) {
        return res.status(400).json({
          error: `Item at index ${i} is invalid: ingredientId and positive quantity are required`,
        });
      }
    }

    // Verify menu belongs to this outlet
    const menu = await prisma.menu.findFirst({
      where: { id: menuId, outletId },
    });

    if (!menu) {
      return res.status(404).json({ error: 'Menu not found in this outlet' });
    }

    // Verify all ingredients exist
    const ingredientIds = items.map((item) => item.ingredientId);
    const existingIngredients = await prisma.ingredient.findMany({
      where: { id: { in: ingredientIds } },
      select: { id: true },
    });
    const existingIds = new Set(existingIngredients.map((i) => i.id));

    for (const item of items) {
      if (!existingIds.has(item.ingredientId)) {
        return res.status(400).json({ error: `Ingredient ${item.ingredientId} not found` });
      }
    }

    // Atomic replace: delete existing + create new in transaction
    const recipes = await prisma.$transaction(async (tx) => {
      // Delete all existing recipes for this menu
      await tx.recipe.deleteMany({ where: { menuId } });

      // Create new recipes
      if (items.length === 0) return [];

      return tx.recipe.createManyAndReturn({
        data: items.map((item) => ({
          menuId,
          ingredientId: item.ingredientId,
          quantity: item.quantity,
          prepQuantity: item.prepQuantity ?? null,
          isOptional: item.isOptional ?? false,
          prepInstruction: item.prepInstruction ?? null,
        })),
        include: {
          ingredient: { select: { id: true, name: true, unit: true, costPerUnit: true, yieldPercent: true } },
        },
      });
    });

    res.json(recipes);
  } catch (err: any) {
    res.status(500).json({ error: 'Failed to replace recipes', message: err.message });
  }
});

// @FLOW:     RECIPE_UPDATE
// @CALLS:    DB:recipes UPDATE
// @MUTATES:  DB:recipes (UPDATE)
recipeRouter.put('/outlets/:id/menus/:menuId/recipes/:recipeId', async (req, res) => {
  try {
    const { id: outletId, menuId, recipeId } = req.params;
    const { quantity, prepQuantity, isOptional, prepInstruction } = req.body;

    // Verify recipe belongs to this menu (and indirectly to this outlet)
    const existing = await prisma.recipe.findFirst({
      where: { id: recipeId, menuId },
    });

    if (!existing) {
      return res.status(404).json({ error: 'Recipe not found' });
    }

    const data: any = {};
    if (quantity !== undefined) data.quantity = quantity;
    if (prepQuantity !== undefined) data.prepQuantity = prepQuantity;
    if (isOptional !== undefined) data.isOptional = isOptional;
    if (prepInstruction !== undefined) data.prepInstruction = prepInstruction;

    const recipe = await prisma.recipe.update({
      where: { id: recipeId },
      data,
      include: {
        ingredient: { select: { id: true, name: true, unit: true, costPerUnit: true, yieldPercent: true } },
      },
    });

    res.json(recipe);
  } catch (err: any) {
    res.status(500).json({ error: 'Failed to update recipe', message: err.message });
  }
});

// @FLOW:     RECIPE_DELETE
// @CALLS:    DB:recipes DELETE
// @MUTATES:  DB:recipes (DELETE)
recipeRouter.delete('/outlets/:id/menus/:menuId/recipes/:recipeId', async (req, res) => {
  try {
    const { id: outletId, menuId, recipeId } = req.params;

    // Verify recipe belongs to this menu
    const existing = await prisma.recipe.findFirst({
      where: { id: recipeId, menuId },
    });

    if (!existing) {
      return res.status(404).json({ error: 'Recipe not found' });
    }

    await prisma.recipe.delete({ where: { id: recipeId } });

    res.json({ deleted: true });
  } catch (err: any) {
    res.status(500).json({ error: 'Failed to delete recipe', message: err.message });
  }
});
