/**
 * Фоновый poll статуса обновлений + баннер «Обновить / Позже».
 * WespUpdateNotifier.init({ dialog: WespDialog | WespKioskDialog });
 */
(function (global) {
  var DISMISS_KEY = "wesp_update_dismissed";
  var DEFAULT_POLL_MS = 300000;
  var PROGRESS_POLL_MS = 500;

  var opts = {};
  var pollTimer = null;
  var progressTimer = null;
  var lastStatus = null;
  var lastProgress = null;

  function ensureDom() {
    if (document.getElementById("wespUpdateBanner")) return;

    var banner = document.createElement("div");
    banner.id = "wespUpdateBanner";
    banner.setAttribute("role", "region");
    banner.setAttribute("aria-label", "Доступно обновление");
    banner.innerHTML =
      '<div class="wesp-update-banner-inner">' +
      '<div class="wesp-update-banner-text" id="wespUpdateBannerText"></div>' +
      '<div class="wesp-update-banner-changelog" id="wespUpdateBannerChangelog"></div>' +
      '<div class="wesp-update-banner-actions">' +
      '<button type="button" class="wesp-update-banner-btn" id="wespUpdateBannerDetails">Подробнее</button>' +
      '<button type="button" class="wesp-update-banner-btn" id="wespUpdateBannerLater">Позже</button>' +
      '<button type="button" class="wesp-update-banner-btn wesp-update-banner-btn--primary" id="wespUpdateBannerInstall">Обновить</button>' +
      "</div></div>";
    document.body.appendChild(banner);

    var overlay = document.createElement("div");
    overlay.id = "wespUpdateOverlay";
    overlay.setAttribute("aria-hidden", "true");
    overlay.innerHTML =
      '<div class="wesp-update-overlay-panel" role="alertdialog" aria-modal="true">' +
      '<h2 class="wesp-update-overlay-title" id="wespUpdateOverlayTitle">Идёт обновление</h2>' +
      '<p class="wesp-update-overlay-body" id="wespUpdateOverlayBody">Подготовка…</p>' +
      '<div class="wesp-update-progress-wrap" id="wespUpdateProgressWrap">' +
      '<div class="wesp-update-progress-track">' +
      '<div class="wesp-update-progress-bar" id="wespUpdateProgressBar"></div>' +
      "</div>" +
      '<div class="wesp-update-progress-meta">' +
      '<span class="wesp-update-progress-percent" id="wespUpdateProgressPercent">0%</span>' +
      '<span class="wesp-update-progress-detail" id="wespUpdateProgressDetail"></span>' +
      "</div>" +
      "</div>" +
      "</div>";
    document.body.appendChild(overlay);

    document.getElementById("wespUpdateBannerLater").addEventListener("click", dismissBanner);
    document.getElementById("wespUpdateBannerDetails").addEventListener("click", toggleDetails);
    document.getElementById("wespUpdateBannerInstall").addEventListener("click", onInstallClick);
  }

  function isDismissed(version) {
    try {
      return sessionStorage.getItem(DISMISS_KEY) === String(version || "");
    } catch (e) {
      return false;
    }
  }

  function dismissBanner() {
    if (lastStatus && lastStatus.pending_version) {
      try {
        sessionStorage.setItem(DISMISS_KEY, String(lastStatus.pending_version));
      } catch (e) {}
    }
    hideBanner();
  }

  function hideBanner() {
    var el = document.getElementById("wespUpdateBanner");
    if (el) {
      el.classList.remove("wesp-update-banner--visible", "wesp-update-banner--expanded");
    }
  }

  function showBanner(status) {
    if (!status || !status.update_available || !status.pending_version) {
      hideBanner();
      return;
    }
    if (isDismissed(status.pending_version)) {
      hideBanner();
      return;
    }
    ensureDom();
    var el = document.getElementById("wespUpdateBanner");
    var text = document.getElementById("wespUpdateBannerText");
    var changelog = document.getElementById("wespUpdateBannerChangelog");
    if (!el || !text) return;

    text.innerHTML =
      "Доступна версия <strong>" +
      escapeHtml(status.pending_version) +
      "</strong>" +
      (status.pending_name ? " — " + escapeHtml(status.pending_name) : "") +
      ". Сейчас: <strong>" +
      escapeHtml(status.current_version || "—") +
      "</strong>.";

    if (changelog) {
      changelog.textContent = status.pending_body || "";
      changelog.style.display = status.pending_body ? "" : "none";
    }

    var detailsBtn = document.getElementById("wespUpdateBannerDetails");
    if (detailsBtn) {
      detailsBtn.style.display = status.pending_body ? "" : "none";
    }

    el.classList.add("wesp-update-banner--visible");
  }

  function toggleDetails() {
    var el = document.getElementById("wespUpdateBanner");
    if (el) el.classList.toggle("wesp-update-banner--expanded");
  }

  function showInstallingOverlay(message, progress) {
    ensureDom();
    var overlay = document.getElementById("wespUpdateOverlay");
    if (overlay) {
      overlay.classList.add("wesp-update-overlay--visible");
      overlay.setAttribute("aria-hidden", "false");
    }
    if (message) {
      var bodyEl = document.getElementById("wespUpdateOverlayBody");
      if (bodyEl) bodyEl.textContent = message;
    }
    applyProgressUi(progress);
    hideBanner();
  }

  function hideInstallingOverlay() {
    var overlay = document.getElementById("wespUpdateOverlay");
    if (overlay) {
      overlay.classList.remove("wesp-update-overlay--visible");
      overlay.setAttribute("aria-hidden", "true");
    }
  }

  function applyProgressUi(progress) {
    if (!progress || typeof progress !== "object") return;
    lastProgress = progress;

    var titleEl = document.getElementById("wespUpdateOverlayTitle");
    var bodyEl = document.getElementById("wespUpdateOverlayBody");
    var barEl = document.getElementById("wespUpdateProgressBar");
    var pctEl = document.getElementById("wespUpdateProgressPercent");
    var detailEl = document.getElementById("wespUpdateProgressDetail");

    var pct = Number(progress.percent);
    if (!Number.isFinite(pct)) pct = 0;
    pct = Math.max(0, Math.min(100, Math.round(pct)));

    if (titleEl && progress.target_version) {
      titleEl.textContent = "Обновление до версии " + progress.target_version;
    }
    if (bodyEl && progress.message) {
      bodyEl.textContent = progress.message;
    }
    if (barEl) {
      barEl.style.width = pct + "%";
      barEl.setAttribute("aria-valuenow", String(pct));
    }
    if (pctEl) pctEl.textContent = pct + "%";
    if (detailEl) {
      detailEl.textContent = progress.detail || "";
      detailEl.style.display = progress.detail ? "" : "none";
    }
  }

  function stopProgressPolling() {
    if (progressTimer) {
      clearInterval(progressTimer);
      progressTimer = null;
    }
  }

  function startProgressPolling() {
    stopProgressPolling();
    progressTimer = setInterval(function () {
      fetchStatus().then(function (status) {
        if (!status) return;
        if (status.update_progress) {
          applyProgressUi(status.update_progress);
        } else if (status.is_updating) {
          applyProgressUi({
            message: "Выполняется обновление…",
            percent: lastProgress ? lastProgress.percent : 5,
          });
        }
      });
    }, PROGRESS_POLL_MS);
  }

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

  function fetchStatus() {
    var url = opts.statusUrl || "/api/updates/status";
    return fetch(url, { credentials: "same-origin", cache: "no-store" }).then(function (r) {
      if (r.status === 401 || r.status === 403) return null;
      return r.json().catch(function () {
        return null;
      });
    });
  }

  function applyStatus(status) {
    if (!status || typeof status !== "object") return;
    lastStatus = status;
    if (status.update_available && status.pending_version) {
      try {
        var dismissed = sessionStorage.getItem(DISMISS_KEY);
        if (dismissed && dismissed !== String(status.pending_version)) {
          sessionStorage.removeItem(DISMISS_KEY);
        }
      } catch (e) {}
    }
    showBanner(status);
  }

  function pollOnce() {
    return fetchStatus().then(function (status) {
      applyStatus(status);
    });
  }

  function onInstallClick() {
    var dialog = opts.dialog;
    if (!dialog || typeof dialog.confirm !== "function") {
      if (!global.confirm("Система перезапустится. Продолжить?")) return;
      doInstall();
      return;
    }
    var msg =
      "Будет загружена и установлена версия " +
      (lastStatus && lastStatus.pending_version ? lastStatus.pending_version : "") +
      ".\n\nСистема перезапустится. Продолжить?";
    dialog
      .confirm(msg, {
        title: "Обновление WESP",
        okText: "Обновить",
        cancelText: "Отмена",
        danger: true,
      })
      .then(function (ok) {
        if (ok) doInstall();
      });
  }

  function waitForServerAndReload() {
    var url = opts.statusUrl || "/api/updates/status";
    var attempts = 0;
    var maxAttempts = 90;
    var intervalMs = 2000;

    showInstallingOverlay(
      "Обновление установлено. Ожидаем перезапуск сервера — страница обновится автоматически.",
      { message: "Ожидание перезапуска сервера…", percent: 100, detail: null }
    );

    function scheduleNext() {
      if (attempts >= maxAttempts) {
        var bodyEl = document.getElementById("wespUpdateOverlayBody");
        if (bodyEl) {
          bodyEl.innerHTML =
            "Сервер долго не отвечает. Если перезапуск уже завершился, " +
            '<button type="button" class="wesp-update-banner-btn wesp-update-banner-btn--primary" id="wespUpdateManualReload">Обновить страницу</button>';
          var btn = document.getElementById("wespUpdateManualReload");
          if (btn) btn.addEventListener("click", function () { global.location.reload(); });
        }
        return;
      }
      setTimeout(tick, intervalMs);
    }

    function showRollbackOverlay(state) {
      var ver = (state && (state.previous_version || state.message)) || "—";
      var msg =
        (state && state.message) ||
        "Обновление отменено. Восстановлена предыдущая версия.";
      showInstallingOverlay(msg, {
        message: msg,
        percent: 100,
        target_version: ver,
      });
      var bar = document.getElementById("wespUpdateProgressBar");
      var panel = document.querySelector("#wespUpdateOverlay .wesp-update-overlay-panel");
      if (bar) bar.classList.add("wesp-update-progress-bar--error");
      if (panel) panel.classList.add("wesp-update-overlay-panel--rollback");
      var bodyEl = document.getElementById("wespUpdateOverlayBody");
      if (bodyEl) {
        bodyEl.innerHTML =
          escapeHtml(msg) +
          ' <button type="button" class="wesp-update-banner-btn wesp-update-banner-btn--primary" id="wespUpdateManualReload">Обновить страницу</button>';
        var btn = document.getElementById("wespUpdateManualReload");
        if (btn) btn.addEventListener("click", function () { global.location.reload(); });
      }
    }

    function tick() {
      attempts += 1;
      applyProgressUi({
        message: "Ожидание перезапуска сервера…",
        percent: 100,
        detail: "~" + attempts * 2 + " с",
      });
      fetch(url, { credentials: "same-origin", cache: "no-store" })
        .then(function (r) {
          return r.json().catch(function () { return null; }).then(function (body) {
            return { ok: r.ok, status: r.status, body: body };
          });
        })
        .then(function (res) {
          var st = res.body && res.body.last_update_state;
          if (st && st.status === "rolled_back") {
            showRollbackOverlay(st);
            return;
          }
          if (res.ok || res.status === 401 || res.status === 403) {
            global.location.reload();
            return;
          }
          scheduleNext();
        })
        .catch(function () {
          scheduleNext();
        });
    }

    setTimeout(tick, 3000);
  }

  function doInstall() {
    var targetVersion = lastStatus && lastStatus.pending_version ? lastStatus.pending_version : "";
    showInstallingOverlay("Подготовка к обновлению…", {
      message: "Подготовка к обновлению…",
      percent: 0,
      target_version: targetVersion,
    });
    startProgressPolling();

    var url = opts.installUrl || "/api/updates/install";
    fetch(url, { method: "POST", credentials: "same-origin", headers: { "Content-Type": "application/json" }, body: "{}" })
      .then(function (r) {
        return r.json().catch(function () {
          return {};
        }).then(function (body) {
          return { ok: r.ok, body: body };
        });
      })
      .then(function (res) {
        stopProgressPolling();
        if (!res.ok) {
          hideInstallingOverlay();
          var errMsg = (res.body && (res.body.error || res.body.message)) || "Не удалось установить обновление";
          if (opts.dialog && opts.dialog.alert) {
            opts.dialog.alert(errMsg, { title: "Ошибка обновления", variant: "danger" });
          } else {
            global.alert(errMsg);
          }
          pollOnce();
          return;
        }
        waitForServerAndReload();
      })
      .catch(function () {
        stopProgressPolling();
        hideInstallingOverlay();
        if (opts.dialog && opts.dialog.alert) {
          opts.dialog.alert("Сетевая ошибка при установке обновления.", { title: "Ошибка", variant: "danger" });
        }
      });
  }

  function init(options) {
    opts = options || {};
    if (!opts.dialog) {
      opts.dialog = global.WespDialog || global.WespKioskDialog || null;
    }
    ensureDom();
    pollOnce();
    var interval = Number(opts.pollIntervalMs);
    if (!Number.isFinite(interval) || interval < 60000) interval = DEFAULT_POLL_MS;
    if (pollTimer) clearInterval(pollTimer);
    pollTimer = setInterval(pollOnce, interval);
  }

  global.WespUpdateNotifier = {
    init: init,
    pollOnce: pollOnce,
    dismissBanner: dismissBanner,
  };
})(typeof window !== "undefined" ? window : globalThis);
