import { type DataTable, Given, Then, When } from "@badeball/cypress-cucumber-preprocessor";

const tomato = {
  id: 1,
  key: "tomato",
  icon: "VEGETABLE",
  category: "freshProduce",
  subcategory: "vegetables",
  allergens: [],
  diets: [{ id: 2, key: "vegetarian" }],
};
const egg = {
  id: 2,
  key: "egg",
  icon: "EGG",
  category: "dairyAndCheese",
  subcategory: "eggs",
  allergens: [{ id: 1, key: "eggs", kind: "ALLERGY" }],
  diets: [],
};
const carrot = {
  id: 3,
  key: "carrot",
  icon: "VEGETABLE",
  category: "freshProduce",
  subcategory: "vegetables",
  allergens: [],
  diets: [{ id: 2, key: "vegetarian" }],
};

const diets = [
  { id: 1, key: "omnivore" },
  { id: 2, key: "vegetarian" },
];

const pieceUnit = { id: 1, key: "piece", type: "COUNT", toBaseFactor: 1 };
const gramUnit = { id: 2, key: "gram", type: "MASS", toBaseFactor: 1 };

Given("the ingredient and diet catalog is available", () => {
  cy.intercept("GET", "**/reference/ingredients", { statusCode: 200, body: [tomato, egg, carrot] });
  cy.intercept("GET", "**/reference/diets", { statusCode: 200, body: diets });
  cy.intercept("GET", "**/reference/units", { statusCode: 200, body: [pieceUnit, gramUnit] });
});

Given("creating the recipe will succeed and return id {int}", (id: number) => {
  cy.intercept("POST", "**/recipes", { statusCode: 201, body: { id } }).as("createRecipe");
});

When("I visit the new recipe form without a secure random UUID", () => {
  cy.visit("/recettes/nouvelle", {
    onBeforeLoad(win) {
      Object.defineProperty(win.crypto, "randomUUID", {
        value: undefined,
        configurable: true,
      });
    },
  });
});

Then(
  "the recipe creation request should have included name {string}, portions {int}, and ingredient {int} with quantity {int} and unitId {int}",
  (name: string, portions: number, ingredientId: number, quantity: number, unitId: number) => {
    cy.wait("@createRecipe")
      .its("request.body")
      .should("deep.include", {
        name,
        portions,
        ingredients: [{ ingredientId, quantity, unitId }],
      });
  },
);

Then("the picker should offer to add {string} as a placeholder", (name: string) => {
  cy.get(".ingredient-picker__add-placeholder").should("contain.text", name);
});

When("I add {string} as a placeholder ingredient", () => {
  // The search field already holds the query from the previous step, so the
  // "add « … »" button carries the right name.
  cy.get(".ingredient-picker__add-placeholder").click();
});

Then("the recipe should include the placeholder ingredient {string}", (name: string) => {
  cy.contains(".ingredient-row__name", name)
    .find(".ingredient-row__placeholder-badge")
    .should("be.visible");
});

Then(
  "the recipe creation request should have included a placeholder ingredient {string} with quantity {int} and unitId {int}",
  (placeholderName: string, quantity: number, unitId: number) => {
    cy.wait("@createRecipe")
      .its("request.body.ingredients")
      .should("deep.equal", [{ placeholderName, quantity, unitId }]);
  },
);

Given("recipe 7 exists with an egg omelette", () => {
  const existingRecipe = {
    id: 7,
    name: "Omelette",
    description: null,
    picture: null,
    portions: 2,
    authorId: 1,
    visibility: "PERSONAL",
    allergens: [{ id: 1, key: "eggs", kind: "ALLERGY" }],
    diets: [],
    isFavorite: false,
    ingredients: [{ ingredient: egg, quantity: 3, unit: pieceUnit }],
    steps: [{ id: 1, description: "Battre les œufs.", picture: null, order: 0 }],
  };
  cy.intercept("GET", "**/recipes/7", { statusCode: 200, body: existingRecipe });
});

Given("updating recipe 7 will succeed", () => {
  cy.intercept("PATCH", "**/recipes/7", { statusCode: 200, body: { id: 7 } }).as("updateRecipe");
});

Then(
  "the recipe update request should have included these ingredients:",
  (dataTable: DataTable) => {
    const expected = dataTable.hashes().map((row) => ({
      ingredientId: Number(row.ingredientId),
      quantity: Number(row.quantity),
      unitId: Number(row.unitId),
    }));
    cy.wait("@updateRecipe").its("request.body.ingredients").should("deep.equal", expected);
  },
);
