/**
 * Панель «План на день» внутри hub-модалки «К».
 */
(function (global) {
  const DAILY_PLAN_DISPENSER_KEY = "wesp-daily-plan-dispenser";
  const ALL_DISPENSERS_ID = "__all_dispensers__";
  const ALL_MILLS_ID = "__all_mills__";

  function escapeHtml(value) {
    return String(value ?? "")
      .replace(/&/g, "&amp;")
      .replace(/</g, "&lt;")
      .replace(/>/g, "&gt;")
      .replace(/"/g, "&quot;");
  }

  function formatDistribution(group) {
    if (group?.distributionLabel) return group.distributionLabel;
    const type = group?.distributionType || "percent";
    const value = group?.value ?? "";
    if (type === "heads") return `${value} гол.`;
    return `${value}%`;
  }

  function todayIso() {
    const d = new Date();
    const y = d.getFullYear();
    const m = String(d.getMonth() + 1).padStart(2, "0");
    const day = String(d.getDate()).padStart(2, "0");
    return `${y}-${m}-${day}`;
  }

  function createDailyPlanPanel() {
    let rootEl = null;
    let dateEl = null;
    let dispenserEl = null;
    let contentEl = null;
    let dispensers = [];
    let undoToastTimer = null;

    function getSelectedDispenserId() {
      return dispenserEl?.value || "";
    }

    function getSelectedPlanDate() {
      return planDateValue();
    }

    function notifySuccess(message) {
      try {
        global.WespZootechNotify?.createAdapter?.()?.success?.(message, { skipRecord: true });
      } catch {
        /* ignore */
      }
    }

    function notifyError(message, fallback) {
      try {
        global.WespZootechNotify?.createAdapter?.()?.error?.(message, {
          fallback: fallback || message,
          skipRecord: true,
        });
      } catch {
        /* ignore */
      }
    }

    function renderToolbar() {
      return (
        '<div class="zt-k-hub-plan__toolbar">' +
        '<div class="zt-k-hub-plan__field">' +
        '<label class="form-label">Дата</label>' +
        '<input type="date" class="form-control form-control-sm" data-daily-plan-date>' +
        "</div>" +
        '<div class="zt-k-hub-plan__field">' +
        '<label class="form-label">Кормораздатчик</label>' +
        '<select class="form-control form-control-sm" data-daily-plan-dispenser>' +
        '<option value="">Загрузка…</option></select>' +
        "</div>" +
        '<button type="button" class="btn btn-primary btn-sm zt-k-hub-plan__pdf" data-action="daily-plan-pdf">' +
        '<i class="fas fa-file-pdf"></i> Скачать PDF</button>' +
        "</div>"
      );
    }

    function mount(container) {
      rootEl = container;
      rootEl.innerHTML =
        '<div class="zt-k-hub-plan">' +
        renderToolbar() +
        '<div class="zt-k-hub-plan__content" data-daily-plan-content>' +
        '<div class="zt-k-hub-plan__loading text-muted small">Загрузка плана…</div>' +
        "</div></div>";
      dateEl = rootEl.querySelector("[data-daily-plan-date]");
      dispenserEl = rootEl.querySelector("[data-daily-plan-dispenser]");
      contentEl = rootEl.querySelector("[data-daily-plan-content]");
      if (dateEl) dateEl.value = todayIso();
      dateEl?.addEventListener("change", () => loadPlan());
      dispenserEl?.addEventListener("change", () => {
        if (dispenserEl.value) {
          try {
            localStorage.setItem(DAILY_PLAN_DISPENSER_KEY, dispenserEl.value);
          } catch {
            /* ignore */
          }
        }
        loadPlan();
      });
      rootEl.querySelector("[data-action='daily-plan-pdf']")?.addEventListener("click", downloadPdf);
      rootEl.addEventListener("click", onPanelClick);
      loadDispensers();
    }

    function planDateValue() {
      return dateEl?.value || todayIso();
    }

    async function onPanelClick(event) {
      const btn = event.target.closest("[data-action]");
      if (!btn || !rootEl?.contains(btn)) return;
      const action = btn.dataset.action;
      if (action === "daily-plan-skip-trip") {
        event.preventDefault();
        const recipeId = btn.dataset.recipeId;
        const recipeName = btn.dataset.recipeName || "Рейс";
        if (recipeId) await skipTrip(recipeId, recipeName);
        return;
      }
      if (action === "daily-plan-unskip-trip") {
        event.preventDefault();
        const recipeId = btn.dataset.recipeId;
        if (recipeId) await unskipTrip(recipeId);
        return;
      }
      if (action === "daily-plan-skip-ingredient") {
        event.preventDefault();
        const recipeId = btn.dataset.recipeId;
        const ingredientId = btn.dataset.ingredientId;
        const label = btn.dataset.label || "Компонент";
        if (recipeId && ingredientId) await skipIngredient(recipeId, ingredientId, label);
        return;
      }
      if (action === "daily-plan-unskip-ingredient") {
        event.preventDefault();
        const recipeId = btn.dataset.recipeId;
        const ingredientId = btn.dataset.ingredientId;
        if (recipeId && ingredientId) await unskipIngredient(recipeId, ingredientId);
        return;
      }
      if (action === "daily-plan-skip-unloading-group") {
        event.preventDefault();
        const recipeId = btn.dataset.recipeId;
        const groupId = btn.dataset.groupId;
        const label = btn.dataset.label || "Группа";
        if (recipeId && groupId) await skipUnloadingGroup(recipeId, groupId, label);
        return;
      }
      if (action === "daily-plan-unskip-unloading-group") {
        event.preventDefault();
        const recipeId = btn.dataset.recipeId;
        const groupId = btn.dataset.groupId;
        if (recipeId && groupId) await unskipUnloadingGroup(recipeId, groupId);
        return;
      }
      if (action === "daily-plan-replace-ingredient") {
        event.preventDefault();
        const recipeId = btn.dataset.recipeId;
        const ingredientId = btn.dataset.ingredientId;
        const componentId = btn.dataset.componentId;
        const label = btn.dataset.label || "Компонент";
        if (recipeId && ingredientId && componentId) {
          await openReplaceIngredientModal(recipeId, ingredientId, componentId, label);
        }
        return;
      }
      if (action === "daily-plan-undo-replace-ingredient") {
        event.preventDefault();
        const recipeId = btn.dataset.recipeId;
        const ingredientId = btn.dataset.ingredientId;
        if (recipeId && ingredientId) await undoReplaceIngredient(recipeId, ingredientId);
        return;
      }
      if (action === "daily-plan-undo-adjust-norm") {
        event.preventDefault();
        const componentId = btn.dataset.componentId;
        if (componentId) await undoComponentNormAdjustment(componentId);
      }
    }

    function formatKg(value) {
      const n = Number(value);
      if (!Number.isFinite(n)) return "—";
      if (Number.isInteger(n)) return String(n);
      return n.toFixed(2).replace(/\.?0+$/, "");
    }

    function replacementRowTitle(ing) {
      if (!ing?.replacedToday) return "";
      if (ing.recalculationMode === "dry_matter") {
        return (
          `Пересчёт по СВ: ${formatKg(ing.originalDryMatterPerHead)} кг/гол сохранено, ` +
          `вес ${formatKg(ing.originalWeightPerHead)} → ${formatKg(ing.weightPerHead)} кг/гол ` +
          `(СВ ${formatKg(ing.originalDryMatterPct)}% → ${formatKg(ing.dryMatterPct)}%)`
        );
      }
      return (
        `Пересчёт по весу: ${formatKg(ing.weightPerHead)} кг/гол сохранено, ` +
        `СВ/гол ${formatKg(ing.originalDryMatterPerHead)} → ${formatKg(ing.dryMatterPerHead)} кг/гол`
      );
    }

    function adjustmentRowTitle(ing) {
      if (!ing?.adjustedToday) return "";
      return (
        `Норма в плане: ${formatKg(ing.originalWeightPerHead)} → ${formatKg(ing.weightPerHead)} кг/гол, ` +
        `СВ/гол ${formatKg(ing.originalDryMatterPerHead)} → ${formatKg(ing.dryMatterPerHead)}`
      );
    }

    function skippedIngredientHint(ing) {
      const wph = Number(ing?.baselineWeightPerHead ?? ing?.weightPerHead);
      const total = Number(ing?.baselineTotalKg);
      if (!Number.isFinite(wph) || !Number.isFinite(total)) return "";
      return `Было: ${formatKg(wph)} кг/гол (${formatKg(total)} кг)`;
    }

    function renderSkippedValueCell(hint) {
      if (!hint) {
        return '<td class="zt-k-hub-plan-row--skipped text-muted">—</td>';
      }
      return (
        `<td class="zt-k-hub-plan-row--skipped text-muted zt-k-hub-plan-cell--hint" ` +
        `data-hint="${escapeHtml(hint)}" title="${escapeHtml(hint)}" aria-label="${escapeHtml(hint)}">—</td>`
      );
    }

    function renderPlanDot(title) {
      return (
        `<span class="recipe-skip-badge__dot zt-k-hub-plan-row__skip-dot" ` +
        `title="${escapeHtml(title)}" aria-hidden="true"></span>`
      );
    }

    function renderSkipDot() {
      return renderPlanDot("Исключён из плана на этот день");
    }

    function renderReplaceDot(title) {
      return renderPlanDot(title || "Сегодня заменили компонент в плане");
    }

    function renderAdjustDot(title = "Сегодня изменили норму в плане") {
      return `<span class="zt-k-hub-plan-row__adjust-dot" title="${escapeHtml(title)}" aria-hidden="true"></span>`;
    }

    function renderRowActionBtn(action, attrs, title, iconClass) {
      return (
        `<button type="button" class="btn btn-sm recipe-table-delete-btn zt-k-hub-plan-row__skip" ` +
        `data-action="${action}" ${attrs} title="${escapeHtml(title)}">` +
        `<i class="fas ${iconClass}"></i></button>`
      );
    }

    function renderSkipActionBtn(action, attrs, title) {
      return renderRowActionBtn(action, attrs, title, "fa-times");
    }

    function hubModalEl() {
      return (
        rootEl?.closest(".modal.wesp-shell-modal") ||
        document.getElementById("zootechNotificationCenterModal")
      );
    }

    function planOverlayHost() {
      return hubModalEl() || rootEl?.closest(".modal-content") || rootEl;
    }

    function dismissAllPlanOverlays() {
      hubModalEl()
        ?.querySelectorAll(".zt-k-hub-plan-overlay")
        .forEach((el) => el.remove());
    }

    function appendPlanOverlay(overlay) {
      dismissAllPlanOverlays();
      overlay.setAttribute("data-daily-plan-overlay", "1");
      planOverlayHost()?.appendChild(overlay);
      return overlay;
    }

    function promptSkipDuration(planDate, title = "На какой срок исключить?") {
      const skip = global.WespDailyPlanSkipDuration;
      if (!skip) return Promise.resolve(null);
      return skip.promptSkipDuration({
        planDate,
        title,
        overlayHost: planOverlayHost() || document.body,
        beforeAppend: dismissAllPlanOverlays,
        onError: notifyError,
      });
    }

    function skipDurationBody(planDate, extra = {}, title) {
      const skip = global.WespDailyPlanSkipDuration;
      if (!skip) return Promise.resolve(null);
      return skip.skipDurationBody(planDate, extra, title);
    }

    async function openReplaceIngredientModal(recipeId, ingredientId, componentId, label) {
      const planDate = planDateValue();
      const replaceModal = global.WespDailyPlanReplaceModal;
      if (!replaceModal) return;
      await replaceModal.open({
        componentId,
        label,
        overlayHost: planOverlayHost() || document.body,
        onError: notifyError,
        onPick: async (replacementComponentId, replacementName) => {
          const body = await skipDurationBody(
            planDate,
            { recipeId, ingredientId, replacementComponentId },
            "На какой срок заменить?"
          );
          if (!body) return;
          const resp = await fetch("/api/daily-plan/replacements/ingredients", {
            method: "POST",
            headers: { "Content-Type": "application/json", Accept: "application/json" },
            body: JSON.stringify(body),
          });
          if (!resp.ok) {
            const err = await resp.json().catch(() => ({}));
            throw new Error(err.message || "Не удалось заменить компонент");
          }
          await loadPlan();
          notifySuccess(`Компонент заменён на «${replacementName}»`);
        },
      });
    }

    async function undoReplaceIngredient(recipeId, ingredientId) {
      const planDate = planDateValue();
      try {
        const params = new URLSearchParams({
          recipe_id: recipeId,
          ingredient_id: ingredientId,
          date: planDate,
        });
        const resp = await fetch(`/api/daily-plan/replacements/ingredients?${params.toString()}`, {
          method: "DELETE",
          headers: { Accept: "application/json" },
        });
        if (!resp.ok) {
          const err = await resp.json().catch(() => ({}));
          throw new Error(err.message || "Не удалось отменить замену");
        }
        await loadPlan();
        notifySuccess("Замена отменена");
      } catch (err) {
        notifyError(err.message, "Не удалось отменить замену");
      }
    }

    async function undoComponentNormAdjustment(componentId) {
      const planDate = planDateValue();
      try {
        const params = new URLSearchParams({
          component_id: componentId,
          date: planDate,
        });
        const resp = await fetch(`/api/daily-plan/adjustments/components?${params.toString()}`, {
          method: "DELETE",
          headers: { Accept: "application/json" },
        });
        if (!resp.ok) {
          const err = await resp.json().catch(() => ({}));
          throw new Error(err.message || "Не удалось вернуть норму");
        }
        await loadPlan();
        notifySuccess("Норма возвращена к мастеру");
        if (typeof global.reloadAfterSkipRestore === "function") {
          global.reloadAfterSkipRestore();
        }
      } catch (err) {
        notifyError(err.message, "Не удалось вернуть норму");
      }
    }

    async function skipTrip(recipeId, recipeName) {
      const planDate = planDateValue();
      const body = await skipDurationBody(planDate, { recipeId });
      if (!body) return;
      try {
        const resp = await fetch("/api/daily-plan/skips", {
          method: "POST",
          headers: { "Content-Type": "application/json", Accept: "application/json" },
          body: JSON.stringify(body),
        });
        if (!resp.ok) {
          const err = await resp.json().catch(() => ({}));
          throw new Error(err.message || "Не удалось исключить рейс");
        }
        await loadPlan();
        showUndoToast(
          "daily-plan-unskip-trip",
          `data-recipe-id="${escapeHtml(recipeId)}"`,
          `Рейс «${escapeHtml(recipeName)}» убран из плана.`
        );
      } catch (err) {
        notifyError(err.message, "Не удалось исключить рейс");
      }
    }

    async function unskipTrip(recipeId) {
      const planDate = planDateValue();
      try {
        const params = new URLSearchParams({ recipe_id: recipeId, date: planDate });
        const resp = await fetch(`/api/daily-plan/skips?${params.toString()}`, {
          method: "DELETE",
          headers: { Accept: "application/json" },
        });
        if (!resp.ok) {
          const err = await resp.json().catch(() => ({}));
          throw new Error(err.message || "Не удалось вернуть рейс");
        }
        dismissUndoToast();
        await loadPlan();
        notifySuccess("Рейс снова в плане");
      } catch (err) {
        notifyError(err.message, "Не удалось вернуть рейс");
      }
    }

    async function skipIngredient(recipeId, ingredientId, label) {
      const planDate = planDateValue();
      const body = await skipDurationBody(planDate, { recipeId, ingredientId });
      if (!body) return;
      try {
        const resp = await fetch("/api/daily-plan/skips/ingredients", {
          method: "POST",
          headers: { "Content-Type": "application/json", Accept: "application/json" },
          body: JSON.stringify(body),
        });
        if (!resp.ok) {
          const err = await resp.json().catch(() => ({}));
          throw new Error(err.message || "Не удалось убрать компонент");
        }
        await loadPlan();
        showUndoToast(
          "daily-plan-unskip-ingredient",
          `data-recipe-id="${escapeHtml(recipeId)}" data-ingredient-id="${escapeHtml(ingredientId)}"`,
          `Компонент «${escapeHtml(label)}» убран из плана.`
        );
      } catch (err) {
        notifyError(err.message, "Не удалось убрать компонент");
      }
    }

    async function unskipIngredient(recipeId, ingredientId) {
      const planDate = planDateValue();
      try {
        const params = new URLSearchParams({
          recipe_id: recipeId,
          ingredient_id: ingredientId,
          date: planDate,
        });
        const resp = await fetch(`/api/daily-plan/skips/ingredients?${params.toString()}`, {
          method: "DELETE",
          headers: { Accept: "application/json" },
        });
        if (!resp.ok) {
          const err = await resp.json().catch(() => ({}));
          throw new Error(err.message || "Не удалось вернуть компонент");
        }
        dismissUndoToast();
        await loadPlan();
        notifySuccess("Компонент снова в плане");
      } catch (err) {
        notifyError(err.message, "Не удалось вернуть компонент");
      }
    }

    async function skipUnloadingGroup(recipeId, groupId, label) {
      const planDate = planDateValue();
      const body = await skipDurationBody(planDate, { recipeId, unloadingGroupId: groupId });
      if (!body) return;
      try {
        const resp = await fetch("/api/daily-plan/skips/unloading-groups", {
          method: "POST",
          headers: { "Content-Type": "application/json", Accept: "application/json" },
          body: JSON.stringify(body),
        });
        if (!resp.ok) {
          const err = await resp.json().catch(() => ({}));
          throw new Error(err.message || "Не удалось убрать группу");
        }
        await loadPlan();
        showUndoToast(
          "daily-plan-unskip-unloading-group",
          `data-recipe-id="${escapeHtml(recipeId)}" data-group-id="${escapeHtml(groupId)}"`,
          `Группа «${escapeHtml(label)}» убрана из плана.`
        );
      } catch (err) {
        notifyError(err.message, "Не удалось убрать группу");
      }
    }

    async function unskipUnloadingGroup(recipeId, groupId) {
      const planDate = planDateValue();
      try {
        const params = new URLSearchParams({
          recipe_id: recipeId,
          unloading_group_id: groupId,
          date: planDate,
        });
        const resp = await fetch(
          `/api/daily-plan/skips/unloading-groups?${params.toString()}`,
          { method: "DELETE", headers: { Accept: "application/json" } }
        );
        if (!resp.ok) {
          const err = await resp.json().catch(() => ({}));
          throw new Error(err.message || "Не удалось вернуть группу");
        }
        dismissUndoToast();
        await loadPlan();
        notifySuccess("Группа снова в плане");
      } catch (err) {
        notifyError(err.message, "Не удалось вернуть группу");
      }
    }

    function dismissUndoToast() {
      if (undoToastTimer) {
        clearTimeout(undoToastTimer);
        undoToastTimer = null;
      }
      rootEl?.querySelector("[data-daily-plan-undo]")?.remove();
    }

    function showUndoToast(unskipAction, dataAttrs, message) {
      dismissUndoToast();
      const toast = document.createElement("div");
      toast.className = "zt-k-hub-plan__undo-toast";
      toast.dataset.dailyPlanUndo = "1";
      toast.innerHTML =
        `<span>${message}</span>` +
        `<button type="button" class="btn btn-sm btn-link zt-k-hub-plan__undo-btn" ` +
        `data-action="${unskipAction}" ${dataAttrs}>Отменить</button>`;
      rootEl?.querySelector(".zt-k-hub-plan")?.appendChild(toast);
      undoToastTimer = setTimeout(() => dismissUndoToast(), 8000);
    }

    async function loadDispensers() {
      try {
        const resp = await fetch("/api/feed_dispensers?limit=200");
        if (!resp.ok) throw new Error("dispensers");
        const data = await resp.json();
        dispensers = Array.isArray(data) ? data : [];
        if (!dispenserEl) return;
        if (!dispensers.length) {
          dispenserEl.innerHTML = '<option value="">Нет кормораздатчиков</option>';
          renderEmpty("Добавьте кормораздатчик в разделе «Кормораздатчики».");
          return;
        }
        const saved = (() => {
          try {
            return localStorage.getItem(DAILY_PLAN_DISPENSER_KEY) || "";
          } catch {
            return "";
          }
        })();
        const dispenserItems = dispensers.filter((d) => d.type !== "mill");
        const millItems = dispensers.filter((d) => d.type === "mill");
        let options =
          `<option value="${ALL_DISPENSERS_ID}"${saved === ALL_DISPENSERS_ID ? " selected" : ""}>Все кормораздатчики</option>`;
        if (dispenserItems.length) {
          options += '<optgroup label="Кормораздатчики">';
          options += dispenserItems
            .map((d) => {
              const id = escapeHtml(d.id);
              const name = escapeHtml(d.name || d.id);
              const selected = d.id === saved ? " selected" : "";
              return `<option value="${id}"${selected}>${name}</option>`;
            })
            .join("");
          options += "</optgroup>";
        }
        options += `<option value="${ALL_MILLS_ID}"${saved === ALL_MILLS_ID ? " selected" : ""}>Все кормоцеха</option>`;
        if (millItems.length) {
          options += '<optgroup label="Кормоцеха">';
          options += millItems
            .map((d) => {
              const id = escapeHtml(d.id);
              const name = escapeHtml(d.name || d.id);
              const selected = d.id === saved ? " selected" : "";
              return `<option value="${id}"${selected}>${name}</option>`;
            })
            .join("");
          options += "</optgroup>";
        }
        dispenserEl.innerHTML = options;
        if (!dispenserEl.value) {
          dispenserEl.value = saved || ALL_DISPENSERS_ID;
        }
        loadPlan();
      } catch {
        if (dispenserEl) {
          dispenserEl.innerHTML = '<option value="">Ошибка загрузки</option>';
        }
        renderEmpty("Не удалось загрузить список кормораздатчиков.");
      }
    }

    function buildPlanUrl(pdf) {
      const params = new URLSearchParams();
      if (dateEl?.value) params.set("date", dateEl.value);
      if (dispenserEl?.value) params.set("dispenser_id", dispenserEl.value);
      const base = pdf ? "/api/daily-plan/pdf" : "/api/daily-plan";
      return `${base}?${params.toString()}`;
    }

    async function loadPlan() {
      if (!contentEl) return;
      if (!dispenserEl?.value) {
        renderEmpty("Выберите кормораздатчик.");
        return;
      }
      contentEl.innerHTML =
        '<div class="zt-k-hub-plan__loading text-muted small">Загрузка плана…</div>';
      try {
        const resp = await fetch(buildPlanUrl(false));
        if (!resp.ok) {
          const err = await resp.json().catch(() => ({}));
          throw new Error(err.message || "Ошибка загрузки");
        }
        const plan = await resp.json();
        renderPlan(plan);
      } catch (err) {
        renderEmpty(global.WespUserMessages?.safe?.(err.message, "Не удалось загрузить план.") || "Не удалось загрузить план.");
      }
    }

    function renderEmpty(message) {
      if (!contentEl) return;
      contentEl.innerHTML =
        '<div class="zt-k-hub-plan__empty">' +
        '<i class="fas fa-calendar-day"></i>' +
        `<p>${escapeHtml(message)}</p></div>`;
    }

    function renderReplaceBtn(recipeId, ing) {
      if (!ing.componentId) return "";
      const label = ing.originalName || ing.name || "Компонент";
      return renderRowActionBtn(
        "daily-plan-replace-ingredient",
        `data-recipe-id="${escapeHtml(recipeId)}" data-ingredient-id="${escapeHtml(ing.id)}" ` +
          `data-component-id="${escapeHtml(ing.componentId)}" data-label="${escapeHtml(label)}"`,
        "Заменить компонент",
        "fa-exchange-alt"
      );
    }

    function renderTotalsColumn(totals, grandTotalKg) {
      if (!totals.length) {
        return (
          '<aside class="zt-k-hub-plan__totals-col">' +
          '<h3 class="zt-k-hub-plan__col-title">Итого по компонентам</h3>' +
          '<p class="zt-k-hub-plan__col-empty text-muted">Нет данных</p></aside>'
        );
      }
      let rows = "";
      totals.forEach((row) => {
        rows += `<tr><td>${escapeHtml(row.name)}</td><td>${escapeHtml(formatKg(row.totalKg))}</td></tr>`;
      });
      const grand =
        grandTotalKg ??
        totals.reduce((sum, row) => sum + Number(row.totalKg || 0), 0);
      return (
        '<aside class="zt-k-hub-plan__totals-col">' +
        '<h3 class="zt-k-hub-plan__col-title">Итого по компонентам</h3>' +
        '<div class="zt-k-hub-plan__col-scroll">' +
        '<table class="zt-k-hub-plan-table zt-k-hub-plan-table--totals">' +
        "<thead><tr><th>Компонент</th><th>Всего, кг</th></tr></thead>" +
        `<tbody>${rows}</tbody>` +
        `<tfoot><tr class="zt-k-hub-plan-table__total-row"><th>Итого</th><th>${escapeHtml(formatKg(grand))}</th></tr></tfoot>` +
        "</table></div></aside>"
      );
    }

    function renderSkippedSection(plan) {
      const skippedTrips = plan.skippedTrips || [];
      if (!skippedTrips.length) return "";
      let rows = "";
      skippedTrips.forEach((trip) => {
        rows +=
          '<li class="zt-k-hub-plan-skipped__item">' +
          `<span>${renderSkipDot()}<span class="text-muted">Рейс:</span> ${escapeHtml(trip.recipeName)}</span>` +
          '<button type="button" class="btn btn-sm btn-outline-success" ' +
          'data-action="daily-plan-unskip-trip" ' +
          `data-recipe-id="${escapeHtml(trip.recipeId)}" title="Вернуть в план">` +
          '<i class="fas fa-undo"></i> Вернуть</button></li>';
      });
      return (
        '<section class="zt-k-hub-plan-skipped">' +
        '<h3 class="zt-k-hub-plan-skipped__title">Исключено из плана</h3>' +
        `<ul class="zt-k-hub-plan-skipped__list">${rows}</ul></section>`
      );
    }

    function renderTripsColumn(periods) {
      let html = '<div class="zt-k-hub-plan__trips-col"><div class="zt-k-hub-plan__col-scroll">';
      periods.forEach((period) => {
        const trips = period.trips || [];
        if (!trips.length) return;
        html +=
          `<section class="zt-k-hub-plan__period"><h3 class="zt-k-hub-plan__period-title">${escapeHtml(period.name)}</h3><div class="zt-k-hub-plan__trips">`;
        trips.forEach((trip) => {
          const recipeId = escapeHtml(trip.recipeId);
          const hasAdjustedNorm = (trip.ingredients || []).some((ing) => ing.adjustedToday);
          const hasReplacedIngredient = (trip.ingredients || []).some((ing) => ing.replacedToday);
          const adjustBadge = hasAdjustedNorm
            ? ' <span class="recipe-adjust-badge" title="Сегодня изменили норму в плане">' +
              '<span class="zt-k-hub-plan-row__adjust-dot" aria-hidden="true"></span>сегодня изменили норму</span>'
            : "";
          const replaceBadge = hasReplacedIngredient
            ? ' <span class="recipe-skip-badge" title="Сегодня заменили компонент в плане">' +
              '<span class="recipe-skip-badge__dot" aria-hidden="true"></span>заменён компонент</span>'
            : "";
          const ings = (trip.ingredients || [])
            .map((ing) => {
              const ingId = escapeHtml(ing.id);
              const name = escapeHtml(ing.name);
              const skipped = Boolean(ing.skippedToday);
              const replaced = Boolean(ing.replacedToday);
              const adjusted = Boolean(ing.adjustedToday);
              const rowClass = skipped
                ? "zt-k-hub-plan-row--skipped"
                : replaced
                  ? "zt-k-hub-plan-row--replaced"
                  : adjusted
                    ? "zt-k-hub-plan-row--adjusted"
                    : "";
              const replaceTitle = replacementRowTitle(ing);
              const adjustTitle = adjustmentRowTitle(ing);
              const skipHint = skipped ? skippedIngredientHint(ing) : "";
              const nameCell = skipped
                ? `<td class="zt-k-hub-plan-row--skipped">${renderSkipDot()}${name}</td>`
                : replaced
                  ? `<td class="zt-k-hub-plan-row--replaced" title="${escapeHtml(replaceTitle)}">${renderReplaceDot(replaceTitle)}${name}</td>`
                  : adjusted
                    ? `<td class="zt-k-hub-plan-row--adjusted" title="${escapeHtml(adjustTitle)}">${renderAdjustDot(adjustTitle)}${name}</td>`
                    : `<td>${name}</td>`;
              const weightCell = skipped
                ? renderSkippedValueCell(skipHint)
                : `<td>${escapeHtml(formatKg(ing.weightPerHead))}</td>`;
              const totalCell = skipped
                ? renderSkippedValueCell(skipHint)
                : `<td>${escapeHtml(formatKg(ing.totalKg))}</td>`;
              let actionCell = "";
              if (ing.id) {
                if (skipped) {
                  actionCell = renderRowActionBtn(
                    "daily-plan-unskip-ingredient",
                    `data-recipe-id="${recipeId}" data-ingredient-id="${ingId}"`,
                    "Вернуть в план",
                    "fa-undo"
                  );
                } else {
                  if (replaced) {
                    actionCell += renderRowActionBtn(
                      "daily-plan-undo-replace-ingredient",
                      `data-recipe-id="${recipeId}" data-ingredient-id="${ingId}"`,
                      "Отменить замену",
                      "fa-undo"
                    );
                  } else if (adjusted && ing.componentId) {
                    actionCell += renderRowActionBtn(
                      "daily-plan-undo-adjust-norm",
                      `data-component-id="${escapeHtml(ing.componentId)}"`,
                      "Вернуть норму",
                      "fa-undo"
                    );
                  } else {
                    actionCell += renderReplaceBtn(recipeId, ing);
                  }
                  actionCell += renderSkipActionBtn(
                    "daily-plan-skip-ingredient",
                    `data-recipe-id="${recipeId}" data-ingredient-id="${ingId}" data-label="${escapeHtml(ing.originalName || ing.name)}"`,
                    "Убрать компонент из плана на этот день"
                  );
                }
              }
              return (
                `<tr class="${rowClass}">` +
                `${nameCell}${weightCell}${totalCell}` +
                `<td class="zt-k-hub-plan-table__actions zt-k-hub-plan-table__actions--multi">${actionCell}</td></tr>`
              );
            })
            .join("");
          const groups = (trip.unloadingGroups || [])
            .map((g) => {
              const groupId = escapeHtml(g.id);
              const name = escapeHtml(g.name);
              const skipped = Boolean(g.skippedToday);
              const nameCell = skipped
                ? `<td class="zt-k-hub-plan-row--skipped">${renderSkipDot()}${name}</td>`
                : `<td>${name}</td>`;
              const weightCell = skipped
                ? '<td class="zt-k-hub-plan-row--skipped text-muted">—</td>'
                : `<td>${escapeHtml(g.weightKg)}</td>`;
              const distCell = skipped
                ? '<td class="zt-k-hub-plan-row--skipped text-muted">—</td>'
                : `<td>${escapeHtml(formatDistribution(g))}</td>`;
              let actionCell = "";
              if (g.id) {
                if (skipped) {
                  actionCell = renderRowActionBtn(
                    "daily-plan-unskip-unloading-group",
                    `data-recipe-id="${recipeId}" data-group-id="${groupId}"`,
                    "Вернуть в план",
                    "fa-undo"
                  );
                } else {
                  actionCell = renderSkipActionBtn(
                    "daily-plan-skip-unloading-group",
                    `data-recipe-id="${recipeId}" data-group-id="${groupId}" data-label="${name}"`,
                    "Убрать группу из плана на этот день"
                  );
                }
              }
              return (
                `<tr class="${skipped ? "zt-k-hub-plan-row--skipped" : ""}">` +
                `${nameCell}${weightCell}${distCell}` +
                `<td class="zt-k-hub-plan-table__actions">${actionCell}</td></tr>`
              );
            })
            .join("");
          html +=
            '<article class="zt-k-hub-plan-trip zt-card">' +
            '<div class="zt-k-hub-plan-trip__head">' +
            `<h4 class="zt-k-hub-plan-trip__title">${escapeHtml(trip.recipeName)}${replaceBadge}${adjustBadge}` +
            ` <span class="text-muted">(${escapeHtml(trip.headsPerTrip)} гол., ${escapeHtml(trip.mixingTimeSec)} с)</span></h4>` +
            '<button type="button" class="btn btn-sm recipe-table-delete-btn zt-k-hub-plan-trip__skip" ' +
            'data-action="daily-plan-skip-trip" ' +
            `data-recipe-id="${recipeId}" ` +
            `data-recipe-name="${escapeHtml(trip.recipeName)}" ` +
            'title="Убрать из плана на этот день">' +
            '<i class="fas fa-trash"></i></button></div>' +
            '<table class="zt-k-hub-plan-table"><thead><tr><th>Компонент</th><th>кг/гол</th><th>Всего, кг</th><th></th></tr></thead>' +
            `<tbody>${ings || '<tr><td colspan="4" class="text-muted">—</td></tr>'}</tbody>` +
            `<tfoot><tr class="zt-k-hub-plan-table__total-row"><td>Итого по рейсу</td><td></td><td>${escapeHtml(formatKg(trip.totalWeightKg))}</td><td></td></tr></tfoot></table>`;
          if (groups) {
            html +=
              '<p class="zt-k-hub-plan-trip__sub">Выгрузка</p>' +
              '<table class="zt-k-hub-plan-table"><thead><tr><th>Группа</th><th>кг</th><th>Распределение</th><th></th></tr></thead>' +
              `<tbody>${groups}</tbody></table>`;
          }
          html += "</article>";
        });
        html += "</div></section>";
      });
      html += "</div></div>";
      return html;
    }

    function renderPlan(plan) {
      if (!contentEl) return;
      const periods = plan.periods || [];
      const skippedTrips = plan.skippedTrips || [];
      const hasTrips = periods.some((p) => (p.trips || []).length);
      const hasSkipped = skippedTrips.length;
      if (!hasTrips && !hasSkipped) {
        renderEmpty("Нет периодов или рейсов для выбранного кормораздатчика.");
        return;
      }

      contentEl.innerHTML =
        '<div class="zt-k-hub-plan__split">' +
        renderTotalsColumn(plan.ingredientTotals || [], plan.ingredientGrandTotalKg) +
        renderTripsColumn(periods) +
        "</div>" +
        renderSkippedSection(plan);
    }

    function downloadPdf() {
      if (!dispenserEl?.value) return;
      global.open(buildPlanUrl(true), "_blank", "noopener");
    }

    function destroy() {
      dismissUndoToast();
      dismissAllPlanOverlays();
      if (rootEl) {
        rootEl.removeEventListener("click", onPanelClick);
        rootEl.innerHTML = "";
      }
      rootEl = null;
      dateEl = null;
      dispenserEl = null;
      contentEl = null;
    }

    return {
      mount,
      destroy,
      dismissAllPlanOverlays,
      reload: loadPlan,
      getSelectedDispenserId,
      getSelectedPlanDate,
    };
  }

  let activePanel = null;

  global.WespDailyPlanPanel = {
    createDailyPlanPanel,
    _setActivePanel(panel) {
      activePanel = panel || null;
    },
    getSelectedDispenserId() {
      return activePanel?.getSelectedDispenserId?.() || "";
    },
    getSelectedPlanDate() {
      return activePanel?.getSelectedPlanDate?.() || todayIso();
    },
    reload() {
      return activePanel?.reload?.();
    },
  };
})(typeof window !== "undefined" ? window : globalThis);
