import { expect } from "@playwright/test";
import { userTest as test } from "../fixtures";
import {
  loginByEmailAndPassword,
  goToJournal,
  goToRecipes,
  cookRecipeFromJournal,
  goToLeftovers,
  addRecipeToMealPlan,
} from "../helpers";
import { COOKED_MEAL_INGREDIENT_TITLE } from "@cookterra/shared";
import openIngredientBottomSheet from "../helpers/ingredient/openIngredientBottomSheet";
import markIngredientAsInStock from "../helpers/ingredient/markIngredientAsInStock";

test("user can mark planned recipe as cooked and find cooked meal in leftovers", async ({
  page,
  user,
}) => {
  const RECIPE_TITLE = "Макароны по-флотски";

  await loginByEmailAndPassword(page, user.email, user.password);

  // Step 1: Navigate to journal and cook recipe directly
  await goToJournal(page);
  await cookRecipeFromJournal(page, RECIPE_TITLE);

  // Step 2: Navigate to leftovers and verify cooked meal behavior
  await goToLeftovers(page);

  // Verify that cooked does not appear in leftovers under "Готовая еда"
  await expect(page.getByText("Готовая еда")).not.toBeVisible();
  await expect(
    page.getByRole("link").filter({ hasText: COOKED_MEAL_INGREDIENT_TITLE }),
  ).not.toBeVisible();
  await expect(
    page.getByRole("link").filter({ hasText: RECIPE_TITLE }),
  ).not.toBeVisible();
});

test("user can cook recipe and see stock deducted correctly", async ({
  page,
  user,
}) => {
  // Clean meal plans
  await user.kitchen.cleanMealPlans();

  // Create a test recipe with 4 ingredients with different quantity types
  const recipeTitle = "Тестовое блюдо для проверки запасов";
  await user.createRecipe({
    title: recipeTitle,
    servings: 2,
    ingredients: [
      ["Говядина", "WEIGHT", 300], // Will add exact match (300g)
      ["Яйцо куриное", "QUANTITY", 2], // Will add double (4)
      ["Помидоры", "WEIGHT", 200], // Will add rough "left some"
      ["Молоко", "VOLUME", 0.5], // Will add in same unit (milliliters) so the assertion doesn't depend on a learned weight↔volume conversion rule
      "Соль", // Will add specific quantity (500g)
      "Перец чёрный", // Will add rough "left some"
    ],
    dishTypes: ["Main course"],
  });

  // Login to the app
  await loginByEmailAndPassword(page, user.email, user.password);

  // Navigate to recipes to access the created recipe
  await goToRecipes(page);
  await page
    .getByRole("button", {
      name: recipeTitle,
    })
    .click();

  // Wait for recipe details page to load
  await expect(page.getByRole("heading", { name: recipeTitle })).toBeVisible();

  // Set quantity for "Говядина" (300g)
  await openIngredientBottomSheet(page, "Говядина");
  await markIngredientAsInStock(page, "Говядина", "Граммы", 300);

  // Set quantity for "Яйцо куриное" (4)
  await openIngredientBottomSheet(page, "Яйцо куриное");
  await markIngredientAsInStock(page, "Яйцо куриное", "Штуки", 4);

  // Set quantity for "Помидоры" (left some)
  await openIngredientBottomSheet(page, "Помидоры");
  await markIngredientAsInStock(page, "Помидоры", "Примерно");

  // Set quantity for "Молоко" (1000 мл = 1 л) — same unit as recipe (volume)
  await openIngredientBottomSheet(page, "Молоко");
  await markIngredientAsInStock(page, "Молоко", "Миллилитры", 1000);

  // Set quantity for "Соль" (500g)
  await openIngredientBottomSheet(page, "Соль");
  await markIngredientAsInStock(page, "Соль", "Граммы", 500);

  // Set quantity for "Перец чёрный" (left some)
  await openIngredientBottomSheet(page, "Перец чёрный");
  await markIngredientAsInStock(page, "Перец чёрный", "Примерно");

  // Navigate to journal and plan recipe
  await goToJournal(page);

  // Add recipe to meal plan
  await addRecipeToMealPlan(page, recipeTitle, "Ужин");

  // Mark recipe as cooked
  await page
    .getByRole("region", { name: recipeTitle })
    .getByRole("button", {
      name: "Готово",
    })
    .click();

  // Modal should appear
  await expect(page.getByRole("presentation")).toBeVisible();

  // Говядина: 300 г - 300 г = не осталось
  await expect(page.getByTestId(`QuantityUsed-Говядина`)).toHaveText("-300 г");
  await expect(page.getByTestId(`QuantityBefore-Говядина`)).toHaveText("300 г");
  // await expect(page.getByTestId(`QuantityAfter-Говядина`)).toHaveText(
  //   "не осталось",
  // );

  // Яйцо куриное: 4 шт - 2 шт = 2 шт
  await expect(page.getByTestId(`QuantityUsed-Яйцо куриное`)).toHaveText(
    "-2 шт",
  );
  await expect(page.getByTestId(`QuantityBefore-Яйцо куриное`)).toHaveText(
    "4 шт",
  );
  await expect(page.getByTestId(`QuantityAfter-Яйцо куриное`)).toHaveText(
    "2 шт",
  );

  // Помидоры: есть - 200 г = есть
  await expect(page.getByTestId(`QuantityUsed-Помидоры`)).toHaveText("-200 г");
  await expect(page.getByTestId(`QuantityBefore-Помидоры`)).toHaveText("есть");
  await expect(page.getByTestId(`QuantityAfter-Помидоры`)).not.toBeVisible();

  // Молоко: 1 л - 500 мл = 500 мл (same unit, no cross-unit conversion)
  await expect(page.getByTestId(`QuantityUsed-Молоко`)).toHaveText("-500 мл");
  await expect(page.getByTestId(`QuantityBefore-Молоко`)).toHaveText("1 л");
  await expect(page.getByTestId(`QuantityAfter-Молоко`)).toHaveText("500 мл");

  // Соль: 500 г - по вкусу = есть
  await expect(page.getByTestId(`QuantityUsed-Соль`)).toHaveText("по вкусу");
  await expect(page.getByTestId(`QuantityBefore-Соль`)).toHaveText("500 г");
  await expect(page.getByTestId(`QuantityAfter-Соль`)).toHaveText("есть");

  // Перец чёрный: есть - по вкусу = есть
  await expect(page.getByTestId(`QuantityUsed-Перец чёрный`)).toHaveText(
    "по вкусу",
  );
  await expect(page.getByTestId(`QuantityBefore-Перец чёрный`)).toHaveText(
    "есть",
  );
  await expect(
    page.getByTestId(`QuantityAfter-Перец чёрный`),
  ).not.toBeVisible();

  // Confirm cooking
  await page.getByRole("button", { name: "Подтвердить" }).click();

  // "Mark as cooked" button should not be visible
  await expect(
    page.getByRole("region", { name: recipeTitle }).getByRole("button", {
      name: "Готово",
    }),
  ).not.toBeVisible();

  // Navigate to leftovers to verify stock levels
  await goToLeftovers(page);

  const getLeftoverLabel = (ingredientName: string) =>
    page.getByTestId(`LeftoverLabel-${ingredientName}`);

  // 5 ingredients should stay in stock
  await expect(getLeftoverLabel("Яйцо куриное")).toHaveText("2 шт");
  await expect(getLeftoverLabel("Помидоры")).toHaveText("есть");
  await expect(getLeftoverLabel("Молоко")).toHaveText("500 мл");
  await expect(getLeftoverLabel("Соль")).toHaveText("есть");
  await expect(getLeftoverLabel("Перец чёрный")).toHaveText("есть");

  // One ingredient should be gone
  await expect(getLeftoverLabel("Говядина")).not.toBeVisible();
});

test("confirm cooking should not send Infinity when ingredient unit is changed to roughly", async ({
  page,
  user,
}) => {
  await user.kitchen.cleanMealPlans();

  const recipeTitle = "Тест Infinity бага";
  await user.createRecipe({
    title: recipeTitle,
    servings: 2,
    ingredients: [["Говядина", "WEIGHT", 300]],
    dishTypes: ["Main course"],
  });

  await loginByEmailAndPassword(page, user.email, user.password);

  // Navigate to journal and add recipe to meal plan
  await goToJournal(page);
  await addRecipeToMealPlan(page, recipeTitle, "Ужин");

  // Click "Готово" to navigate to confirm cooking page
  await page
    .getByRole("region", { name: recipeTitle })
    .getByRole("button", { name: "Готово" })
    .click();

  // Wait for confirm cooking page (renders as full-screen MUI Modal)
  await expect(page.getByRole("presentation")).toBeVisible();

  // Enter edit mode for ingredients
  await page.getByRole("button", { name: "Изменить" }).click();

  // Click the edit icon on "Говядина" to open DeductedQuantityDrawer
  await page
    .getByRole("listitem", { name: "Говядина" })
    .getByRole("button", { name: "Изменить" })
    .click();

  // Wait for the drawer to open
  const drawer = page.getByRole("dialog", { name: /Говядина/ });
  await expect(drawer).toBeVisible();

  // Change unit to "Примерно" — this triggers the Infinity bug
  // because onChange(null) → handleQuantityChange(null) → { value: Infinity }
  await drawer.getByRole("combobox").click();
  await page.getByRole("option", { name: "Примерно" }).click();

  // Confirm in drawer
  await drawer.getByRole("button", { name: "Подтвердить" }).click();
  await expect(drawer).not.toBeVisible();

  // Exit edit mode
  await page.getByRole("button", { name: "Готово" }).click();

  // Click main confirm button
  await page.getByRole("button", { name: "Подтвердить" }).click();

  // Cooking confirmation should succeed: the confirm cooking page (MUI Modal)
  // should close and we should be back on the journal.
  // When the Infinity bug is present, the mutation fails with an error alert
  // and the confirm cooking page stays open.
  await expect(page.getByRole("region", { name: recipeTitle })).toBeVisible({
    timeout: 5000,
  });

  // The "Готово" (mark as cooked) button should no longer be visible
  await expect(
    page
      .getByRole("region", { name: recipeTitle })
      .getByRole("button", { name: "Готово" }),
  ).not.toBeVisible();
});
