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

const oeufs = { id: 2, key: "eggs", kind: "ALLERGY" };

const omelette = {
  id: 2,
  name: "Omelette",
  description: null,
  picture: null,
  portions: 2,
  authorId: 1,
  visibility: "PERSONAL",
  allergens: [oeufs],
  diets: [],
  isFavorite: false,
};

const omeletteDetail = {
  ...omelette,
  description: "Une omelette toute simple.",
  ingredients: [
    {
      ingredient: {
        id: 10,
        key: "egg",
        icon: "EGG",
        category: "dairyAndCheese",
        subcategory: "eggs",
        allergens: [oeufs],
        diets: [],
      },
      quantity: 3,
      unit: { id: 1, key: "piece", type: "COUNT", toBaseFactor: 1 },
    },
  ],
  steps: [
    { id: 1, description: "Battre les œufs.", picture: null, order: 1, techSteps: [] },
    {
      id: 2,
      description: "Cuire à la poêle.",
      picture: null,
      order: 2,
      // "Cuire" -> the `cook` technique, matching real reference-seed-data.ts
      // (`\bcui(re|sez|sant|sson)\b`) — "poêle" itself matches nothing
      // (that's `panFry`'s "sauter", a different word).
      techSteps: [{ techStep: { id: 1, key: "cook" }, start: 0, end: 5, source: "auto" }],
    },
  ],
};

Given("the disliked ingredients list is empty", () => {
  cy.intercept("GET", "**/profile/disliked-ingredients", { statusCode: 200, body: [] });
});

Given("the recipe catalog contains {string}", () => {
  cy.intercept("GET", /\/recipes\?/, { statusCode: 200, body: [omelette] });
});

Given("recipe 2's detail is available", () => {
  cy.intercept("GET", "**/recipes/2", { statusCode: 200, body: omeletteDetail }).as("getRecipe");
});

Given("toggling recipe 2's favorite will succeed", () => {
  cy.intercept("POST", "**/recipes/2/favorite", { statusCode: 204 }).as("favorite");
});

Given("deleting recipe 2 will succeed", () => {
  cy.intercept("DELETE", "**/recipes/2", { statusCode: 204 }).as("deleteRecipe");
});

// Step 2 is `omeletteDetail`'s "Cuire à la poêle." step, whose only
// existing match is `cook` (id 1) — see that fixture above. The response
// mirrors `SubmitTechStepCorrectionResult` (packages/shared): the audit
// record (reassigning the match to `simmer`, id 3, "Mijoter" — see `the
// tech steps reference list has options`, reference-data.steps.ts) plus
// the step's fresh `techSteps`, now showing that same reassignment as a
// `"manual"`-sourced entry — the API applies a correction immediately, it
// doesn't just record it (see `StepTechStepView.source`'s own doc comment).
Given('correcting step 2\'s "Cuire" match will succeed', () => {
  cy.intercept("POST", "**/recipes/2/steps/2/corrections", {
    statusCode: 201,
    body: {
      correction: {
        id: 1,
        start: 0,
        end: 5,
        previousTechStep: { id: 1, key: "cook" },
        correctedTechStep: { id: 3, key: "simmer" },
        createdAt: new Date().toISOString(),
      },
      techSteps: [
        {
          techStep: { id: 3, key: "simmer" },
          start: 0,
          end: 5,
          source: "manual",
          ingredients: [],
          utensils: [],
        },
      ],
    },
  }).as("correction");
});

When("I click the highlighted technique {string}", (text: string) => {
  cy.contains(".step-tech-step", text).click();
});

Then("I should see the technique correction options", () => {
  cy.get(".tech-step-correction-popover").should("be.visible");
});

// Picking a technique only *selects* it — it takes a separate "Valider"
// click to actually submit (room was made for attaching ingredient/utensil
// metadata alongside it, see `TechStepCorrectionPopover.tsx`'s own doc
// comment on its merged editor) — folded into this one step since nothing
// in this scenario cares about that intermediate state on its own. The
// technique catalog is picked via the same searchable `CatalogSearchPicker`
// the ingredient/utensil sub-flows use, scoped to
// `__technique-section` since that same search-and-pick component is
// reused inside this popover for more than just techniques.
When("I choose {string} as the correct technique", (label: string) => {
  cy.contains(
    ".tech-step-correction-popover__technique-section .catalog-search-picker__list button",
    label,
  ).click();
  cy.contains(".tech-step-correction-popover__confirm-button", "Valider").click();
});

Then(
  "the highlighted technique {string} should be marked as a manual correction",
  (text: string) => {
    cy.contains(".step-tech-step", text).should("have.class", "step-tech-step--manual");
  },
);

Then("the correction request should have been made", () => {
  // Asserts the actual span, not just that *a* request fired — a real bug
  // (StepDescription.tsx's click handler reading a shared, still-mutating
  // `offset` variable by reference instead of a value captured at render
  // time) once sent `end` all the way to the end of the description
  // instead of "Cuire"'s own tight [0, 5) span, and a request-fired-only
  // assertion here didn't catch it — found only via manual testing.
  cy.wait("@correction")
    .its("request.body")
    .should("deep.include", { start: 0, end: 5, previousTechStepId: 1 });
});

Then("the recipe {string} should not be visible in the table", (name: string) => {
  cy.contains(".recipe-table__name", name).should("not.exist");
});

Then("the recipe {string} should be marked as favorite", (name: string) => {
  cy.contains(".recipe-table__name", name).find(".recipe-table__fav-mark").should("exist");
});

Then("the recipe {string} should not be marked as favorite", (name: string) => {
  cy.contains(".recipe-table__name", name).find(".recipe-table__fav-mark").should("not.exist");
});

When("I click the favorite star", () => {
  cy.get(".favorite-star-button").click();
});

Then("the favorite request should have been made", () => {
  cy.wait("@favorite");
});

Then("the favorite star should be marked as favorite", () => {
  cy.get(".favorite-star-button").should("have.class", "is-favorite");
});

When("I click {string} in the recipe detail panel", (text: string) => {
  cy.contains(".recipe-detail-panel__danger-button", text).click();
});

When("I confirm the deletion in the recipe detail panel", () => {
  cy.contains(".recipe-detail-panel__danger-button", "Confirmer la suppression").click();
});

Then("the delete request should have been made", () => {
  cy.wait("@deleteRecipe");
});

Then("the URL should match the recipes list", () => {
  cy.url().should("match", /\/recettes\/?$/);
});
