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

// Mocks the API via cy.intercept — this job doesn't run a live backend (see
// .github/workflows/ci.yml); apps/api's own Mocha suite covers real API
// behavior against a real database (see test/sources.test.ts).
//
// "the sources reference list has options"/"the household's enabled
// sources are empty" resolve from cypress/support/step_definitions/ (the
// preprocessor's step-lookup is *not* global across cypress/e2e/ — only a
// feature's own same-named file/directory plus that shared folder are
// searched, see its error message when a step isn't found). recipes.ts
// sits directly in cypress/e2e/ (not that shared folder), so its own
// "the disliked ingredients list is empty"/"the recipe catalog
// contains"/"recipe 2's detail is available" are scoped to recipes.feature
// only — this file redeclares its own minimal equivalents rather than
// relocating shared infra, the same "each spec's own self-contained
// fixtures" precedent recipes.cy.ts already sets alongside recipes.ts.

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

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

Given("recipe 2's detail is available", () => {
  cy.intercept("GET", "**/recipes/2", {
    statusCode: 200,
    body: {
      id: 2,
      name: "Omelette",
      description: null,
      picture: null,
      portions: 2,
      authorId: 1,
      visibility: "PERSONAL",
      allergens: [],
      diets: [],
      isFavorite: false,
      ingredients: [],
      steps: [
        {
          id: 1,
          description: "Cuire à la poêle.",
          picture: null,
          order: 1,
          techSteps: [{ techStep: { id: 1, key: "cook" }, start: 0, end: 5 }],
        },
      ],
    },
  });
});

Given("the household has enabled TheMealDB", () => {
  cy.intercept("GET", "**/house/current/sources", { statusCode: 200, body: [1] });
});

Given("browsing TheMealDB returns some items", () => {
  cy.intercept("GET", "**/sources/theMealDb/browse*", {
    statusCode: 200,
    body: {
      items: [
        {
          externalId: "52795",
          title: "Chicken Handi",
          picture: null,
          url: "https://www.themealdb.com/meal/52795",
          alreadyImported: true,
          recipeId: 2,
        },
        {
          externalId: "9999",
          title: "Fish Pie",
          picture: null,
          url: "https://www.themealdb.com/meal/9999",
          alreadyImported: false,
          recipeId: null,
        },
      ],
      nextCursor: null,
    },
  });
});

/**
 * A second, distinct item from `Given("browsing TheMealDB returns some
 * items")`'s page-1 pair — used by the infinite-scroll/retry scenarios
 * below, which need to tell "the item that only shows up once the *next*
 * page has loaded" apart from what's already visible on page 1.
 */
const BEEF_WELLINGTON_ITEM = {
  externalId: "77123",
  title: "Beef Wellington",
  picture: null,
  url: "https://www.themealdb.com/meal/77123",
  alreadyImported: false,
  recipeId: null,
};

const CHICKEN_HANDI_AND_FISH_PIE_PAGE_1 = {
  items: [
    {
      externalId: "52795",
      title: "Chicken Handi",
      picture: null,
      url: "https://www.themealdb.com/meal/52795",
      alreadyImported: true,
      recipeId: 2,
    },
    {
      externalId: "9999",
      title: "Fish Pie",
      picture: null,
      url: "https://www.themealdb.com/meal/9999",
      alreadyImported: false,
      recipeId: null,
    },
  ],
  nextCursor: "2",
};

Given("browsing TheMealDB returns two pages of items", () => {
  cy.intercept("GET", "**/sources/theMealDb/browse*", (req) => {
    const isNextPage = req.url.includes("cursor=");
    req.reply({
      statusCode: 200,
      body: isNextPage
        ? { items: [BEEF_WELLINGTON_ITEM], nextCursor: null }
        : CHICKEN_HANDI_AND_FISH_PIE_PAGE_1,
    });
  });
});

// The panel prefetches the next page as soon as page 1 is on screen (before
// anyone's actually waited on it), so the *first* request for it is that
// prefetch — this is what actually fails "once", not a request triggered by
// a click. `handleLoadMore`'s own retry then makes a genuinely fresh
// request (see its own doc comment on why a failed prefetch gets cleared),
// which is the one that succeeds here.
Given("browsing TheMealDB's next page fails once, then succeeds", () => {
  let nextPageAttempts = 0;
  cy.intercept("GET", "**/sources/theMealDb/browse*", (req) => {
    if (!req.url.includes("cursor=")) {
      req.reply({ statusCode: 200, body: CHICKEN_HANDI_AND_FISH_PIE_PAGE_1 });
      return;
    }
    nextPageAttempts += 1;
    if (nextPageAttempts === 1) {
      req.reply({ statusCode: 500, body: {} });
    } else {
      req.reply({ statusCode: 200, body: { items: [BEEF_WELLINGTON_ITEM], nextCursor: null } });
    }
  });
});

Then("I should see a message to retry loading more", () => {
  cy.contains(".recipes-page__status--error", "Réessayer").should("be.visible");
});

Given("previewing TheMealDB item {string} is available", (externalId: string) => {
  cy.intercept("GET", `**/sources/theMealDb/preview/${externalId}`, {
    statusCode: 200,
    body: {
      sourceKey: "theMealDb",
      externalId,
      name: "Fish Pie",
      description: null,
      picture: null,
      portions: 4,
      sourceUrl: "https://www.themealdb.com/meal/9999",
      ingredients: [
        {
          rawText: "1 onion",
          quantity: 1,
          ingredient: {
            id: 1,
            key: "onion",
            icon: "VEGETABLE",
            category: "freshProduce",
            subcategory: "vegetables",
            reproducible: false,
            allergens: [],
            diets: [],
          },
          unit: null,
        },
        { rawText: "some mystery paste", quantity: null, ingredient: null, unit: null },
      ],
      steps: [
        {
          description: "Cuire à la poêle.",
          picture: null,
          techSteps: [{ techStep: { id: 1, key: "cook" }, start: 0, end: 5 }],
        },
      ],
    },
  });
});

Then("I should see the source item {string}", (title: string) => {
  cy.contains(".recipe-table__name", title).should("be.visible");
});

When("I click the source item {string}", (title: string) => {
  cy.contains(".recipe-table__name", title).click();
});

Then("the source item {string} should be marked as already imported", (title: string) => {
  cy.contains("tr", title).find(".source-item-table__imported-badge").should("be.visible");
});

// Browsing a source (outside of adding-to-planning, `RecipePickerDialog`'s
// own scenarios in planning.ts) never imports anything — the only action
// this preview offers is a discreet way out to the item's own page.
Then("I should see a discreet link to the item's original page", () => {
  cy.get(".recipe-detail-panel__source-link").should("be.visible");
});
