export function createRecipesOperationsController({
  notyf,
  getSelectedRecipe,
  setSelectedRecipe,
  getSelectedPeriod,
  setSelectedPeriod,
  getSelectedDispenser,
  getCurrentDispenserType,
  showRecipeEdit,
  loadRecipes,
  loadPeriods,
  ensureComponentsLoaded,
  setUnloadingLinkBroken,
  initializeUnloadingLinkButton,
  updateTripPercentFieldState,
  setDryMatterMode,
  loadIngredients,
  loadUnloadingGroups,
  recalculateWeights,
  updateTotalValues,
}) {
  let copiedRecipeData = null;
  let moveRecipeInFlight = false;

  async function deleteRecipe(recipeId) {
    const periodId = getSelectedPeriod();
    const dispenserId = getSelectedDispenser();
    const isMill =
      typeof getCurrentDispenserType === "function" && getCurrentDispenserType() === "mill";
    /** В контексте периода кормораздатчика удаляем только связь с периодом — иначе DELETE /api/recipes глобально убирает рецепт со всех оборудований. */
    const unlinkFromPeriodOnly = Boolean(periodId && dispenserId && !isMill);

    const msg = unlinkFromPeriodOnly
      ? "Удалить этот рейс из выбранного периода? (Рецепт останется в базе, если используется ещё где-то.)"
      : "Вы уверены, что хотите удалить этот рецепт? Он будет удалён для всех привязок.";
    const ok = globalThis.WespKioskDialog
      ? await globalThis.WespKioskDialog.confirm(msg)
      : globalThis.confirm(msg);
    if (!ok) return;

    try {
      const url = unlinkFromPeriodOnly
        ? `/api/feed_dispensers/${encodeURIComponent(dispenserId)}/periods/${encodeURIComponent(periodId)}/recipes/${encodeURIComponent(recipeId)}`
        : `/api/recipes/${encodeURIComponent(recipeId)}`;

      const response = await fetch(url, { method: "DELETE" });
      if (!response.ok) {
        const errorData = await response.json().catch(() => ({}));
        throw new Error(errorData.message || "Ошибка при удалении рейса");
      }

      const result = await response.json().catch(() => ({}));
      notyf.success(result.message || (unlinkFromPeriodOnly ? "Рейс удалён из периода" : "Рейс удален"));

      if (String(getSelectedRecipe() ?? "") === String(recipeId)) {
        setSelectedRecipe(null);
        showRecipeEdit(false);
      }

      if (getSelectedPeriod()) {
        await loadRecipes(getSelectedPeriod());
      }
      if (getSelectedDispenser()) {
        await loadPeriods(getSelectedDispenser());
      }
    } catch (error) {
      console.error("Ошибка при удалении рейса:", error);
      notyf.error(error.message, { fallback: "Ошибка при удалении рейса" });
    }
  }

  async function moveRecipe(recipeId, fromIndex, toIndex) {
    const selectedPeriod = getSelectedPeriod();
    if (!selectedPeriod || fromIndex === toIndex) return;

    if (
      typeof document !== "undefined" &&
      document.body.classList.contains("recipe-period-transfer-active")
    ) {
      notyf.error(
        "Сначала завершите перенос в другой период (кнопка «Вставить здесь») или отмените его (Escape, отпустите вне списка)."
      );
      return;
    }

    if (moveRecipeInFlight) return;

    if (!applyOptimisticRecipeReorder(fromIndex, toIndex)) {
      return;
    }

    moveRecipeInFlight = true;
    try {
      const response = await fetch(`/api/recipes/${encodeURIComponent(recipeId)}/move`, {
        method: "PUT",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ from_index: fromIndex, to_index: toIndex, period_id: selectedPeriod }),
      });

      if (!response.ok) {
        const errorData = await response.json().catch(() => ({}));
        await loadRecipes(selectedPeriod, { skipRecipesSkeleton: true });
        throw new Error(errorData.message || "Ошибка при перемещении рецепта");
      }

      const listEl = document.getElementById("recipesList");
      if (listEl) {
        reindexRecipeListItems(listEl);
      }
    } catch (error) {
      console.error("Ошибка при перемещении рейса:", error);
      notyf.error(error.message, { fallback: "Ошибка при перемещении рейса" });
    } finally {
      moveRecipeInFlight = false;
    }
  }

  function reindexRecipeListItems(listEl) {
    const items = listEl.querySelectorAll(":scope > .list-item[data-recipe-id]");
    items.forEach((item, index) => {
      item.dataset.index = String(index);
      item.querySelectorAll("[data-index]").forEach((el) => {
        el.dataset.index = String(index);
      });
      const upBtn = item.querySelector('[data-action="move-recipe-up"]');
      const downBtn = item.querySelector('[data-action="move-recipe-down"]');
      if (upBtn) upBtn.disabled = index === 0;
      if (downBtn) downBtn.disabled = index === items.length - 1;
    });
  }

  function applyOptimisticRecipeReorder(fromIndex, toIndex) {
    const listEl = document.getElementById("recipesList");
    if (!listEl) return false;
    const items = [...listEl.querySelectorAll(":scope > .list-item[data-recipe-id]")];
    if (
      fromIndex < 0 ||
      toIndex < 0 ||
      fromIndex >= items.length ||
      toIndex >= items.length ||
      fromIndex === toIndex
    ) {
      return false;
    }
    const [moved] = items.splice(fromIndex, 1);
    items.splice(toIndex, 0, moved);
    items.forEach((item) => listEl.appendChild(item));
    reindexRecipeListItems(listEl);
    return true;
  }

  async function moveRecipeUp(recipeId, currentIndex) {
    if (currentIndex === 0) {
      notyf.error("Рейс уже находится в начале списка");
      return;
    }

    try {
      await moveRecipe(recipeId, currentIndex, currentIndex - 1);
    } catch (error) {
      console.error("Ошибка при перемещении рейса:", error);
      notyf.error(error.message, { fallback: "Ошибка при перемещении рейса" });
    }
  }

  async function moveRecipeDown(recipeId, currentIndex) {
    const totalRecipes = document.querySelectorAll("#recipesList .list-item").length;
    if (currentIndex >= totalRecipes - 1) {
      notyf.error("Рейс уже находится в конце списка");
      return;
    }

    try {
      await moveRecipe(recipeId, currentIndex, currentIndex + 1);
    } catch (error) {
      console.error("Ошибка при перемещении рейса:", error);
      notyf.error(error.message, { fallback: "Ошибка при перемещении рейса" });
    }
  }

  async function pasteRecipe(periodId) {
    if (!copiedRecipeData) {
      notyf.error("Буфер пуст. Сначала скопируйте рейс.");
      return;
    }

    try {
      setSelectedPeriod(periodId);
      setSelectedRecipe(null);

      await ensureComponentsLoaded();

      const recipeName = document.getElementById("recipeName");
      if (recipeName) {
        recipeName.value = `${copiedRecipeData.name} (копия)`;
      }

      const headsCount = document.getElementById("headsCount");
      if (headsCount) {
        const h =
          copiedRecipeData.heads_count ??
          copiedRecipeData.headsPerTrip ??
          copiedRecipeData.heads_per_trip ??
          "";
        headsCount.value = h === "" || h == null ? "" : String(h);
      }

      const mixingTime = document.getElementById("mixingTime");
      if (mixingTime) {
        const mt = copiedRecipeData.mixing_time ?? copiedRecipeData.mixingTime;
        mixingTime.value = mt === "" || mt == null ? "" : String(mt);
      }

      const tripPercent = document.getElementById("tripPercent");
      if (tripPercent) {
        const tp = copiedRecipeData.trip_percent ?? copiedRecipeData.tripPercent;
        tripPercent.value = tp === "" || tp == null ? 100 : String(tp);
      }

      const ingredientsTableBody = document.getElementById("ingredientsTableBody");
      if (ingredientsTableBody) {
        ingredientsTableBody.innerHTML = "";
      }

      const unloadingGroupsTableBody = document.getElementById("unloadingGroupsTableBody");
      if (unloadingGroupsTableBody) {
        unloadingGroupsTableBody.innerHTML = "";
      }

      setUnloadingLinkBroken(Boolean(copiedRecipeData.unloading_link_broken));
      initializeUnloadingLinkButton();
      updateTripPercentFieldState();

      setDryMatterMode(false);

      if (copiedRecipeData.ingredients && copiedRecipeData.ingredients.length > 0) {
        await loadIngredients(copiedRecipeData.ingredients);
      }

      const copiedGroups =
        copiedRecipeData.unloading_groups?.length > 0
          ? copiedRecipeData.unloading_groups
          : copiedRecipeData.unloadingGroups;
      if (copiedGroups && copiedGroups.length > 0) {
        await loadUnloadingGroups(copiedGroups);
      }

      showRecipeEdit(true);

      setTimeout(() => {
        Promise.resolve(recalculateWeights()).catch((err) => console.error("Ошибка при расчете:", err));
      }, 100);
      setTimeout(() => {
        Promise.resolve(updateTotalValues()).catch((err) => console.error("Ошибка при расчете:", err));
      }, 100);

      notyf.success("Рейс вставлен из буфера");
    } catch (error) {
      console.error("Ошибка при вставке рейса:", error);
      notyf.error("Ошибка при вставке рейса");
    }
  }

  async function copyRecipe(recipeId) {
    if (!recipeId) {
      notyf.error("Выберите рейс для копирования");
      return;
    }

    try {
      const response = await fetch(`/api/recipes/${recipeId}`);
      if (!response.ok) {
        throw new Error("Ошибка при загрузке рейса");
      }

      const recipe = await response.json();
      copiedRecipeData = {
        name: recipe.name,
        heads_count:
          recipe.heads_count ??
          recipe.headsPerTrip ??
          recipe.heads_per_trip ??
          0,
        mixing_time: recipe.mixing_time ?? recipe.mixingTime ?? 0,
        trip_percent: recipe.trip_percent ?? recipe.tripPercent ?? 100,
        ingredients: (recipe.ingredients || []).map((ing) => ({
          component_id: ing.component_id,
          weight_per_head: ing.weight_per_head,
          amount: ing.amount,
          dry_matter: ing.dry_matter,
          order: ing.order,
        })),
        unloading_link_broken: Boolean(
          recipe.unloading_link_broken ?? recipe.unloadingLinkBroken ?? false
        ),
        unloading_groups: (recipe.unloading_groups || recipe.unloadingGroups || []).map((group) => ({
          name: group.name,
          distribution_type: group.distribution_type ?? group.distributionType ?? "percent",
          value: group.value,
          weight: group.weight,
          order: group.order,
        })),
      };

      updatePasteButtons();
      notyf.success("Рейс скопирован");
    } catch (error) {
      console.error("Ошибка при копировании рейса:", error);
      notyf.error("Ошибка при копировании рейса");
    }
  }

  function updatePasteButtons() {
    const pasteButtons = document.querySelectorAll(".paste-recipe-btn");
    const hasData = copiedRecipeData !== null;

    pasteButtons.forEach((button) => {
      button.disabled = !hasData;
      if (hasData) {
        button.title = `Вставить рейс "${copiedRecipeData.name}"`;
      } else {
        button.title = "Вставить рейс из буфера";
      }
    });
  }

  return {
    deleteRecipe,
    moveRecipe,
    moveRecipeUp,
    moveRecipeDown,
    pasteRecipe,
    copyRecipe,
    updatePasteButtons,
  };
}
