import {
  select_default
} from "./chunk-I6Y4O3RR.js";
import "./chunk-HFNDKYVF.js";

// src/notify.ts
var sseMessageStorageKey = "sjpp-sse-message";
var notifyDiv = setNotifyDiv();
var notifyElem = notifyDiv.node();
var refresh = notifyElem.__ppRefresh;
var sse;
function notify(_data, now) {
  const data = _data.filter((d) => d.status != "ok" || !d.time || now - d.time < 5e3 || refresh.lastCall < d.time);
  const divs = notifyDiv.selectAll(`.sjpp-sse-message`).data(data, (d) => d.key);
  divs.exit().filter((d) => !d.duration).remove();
  divs.style("color", getColor).style("border", getBorder).html(getHtml).each(function(d) {
    if (d.duration) {
      setTimeout(
        () => select_default(this).transition().duration(d.duration || 0).style("opacity", 0).remove(),
        d.duration
      );
    }
  });
  divs.enter().append("div").attr("class", "sjpp-sse-message").style("margin", "5px").style("padding", "5px").style("border", getBorder).style("color", getColor).html(getHtml).each(function(d) {
    if (d.duration) {
      setTimeout(
        () => select_default(this).transition().duration(d.duration).style("opacity", 0).remove(),
        d.duration
      );
    }
  });
  return data;
}
function setNotifyDiv() {
  const divId = `#sjpp-notify-div-sse-refresh`;
  const notifyElem2 = document.body.querySelector(divId);
  let notifyDiv2;
  if (notifyElem2) notifyDiv2 = select_default(notifyElem2);
  else {
    notifyDiv2 = select_default("body").append("div").attr("id", divId.slice(1)).style("position", "fixed").style("top", `16px`).style("right", "10px").style("font-size", "1.2em").style("background-color", "rgba(250, 250, 250, 0.75)").style("z-index", 1e4);
    notifyDiv2.node().__ppRefresh = setRefresh(notifyDiv2);
  }
  return notifyDiv2;
}
function getHtml(d) {
  return `${d.key}: ${d.message}`;
}
function getColor(d) {
  return d.color || (d.status == "ok" ? "green" : "red");
}
function getBorder(d) {
  return `1px solid ${d.color || "#000"}`;
}
function setRefresh(notifyDiv2) {
  const refresh2 = {
    // used in both sessionStorage and serverconfig.features
    key: "sseRefreshMode",
    // default starting mode, may be replaced by:
    // - using the rendered dom.select dropdown (tab-specific behavior)
    // - setting sessionStorage.setItem(/*refresh.key*/, ) manually (tab-specific)
    // - setting serverconfig.features[/*refresh.key*/] (applies across tabs)
    mode: "full_except_on_unhide",
    // available mode options
    modeOptions: {
      appOnly: "call runproteinpaint() on the same DOM element, with the original argument + any HMR state",
      appOnly_except_on_unhide: "same as reload, except when a hidden browser tab is made visible",
      full: "call window.reload() to refresh from URL params and/or runpp() arguments, this may have less memory leaks than the default approach",
      full_except_on_unhide: "same as full reload, except when a hidden browser tab is made visible",
      none: "do not refresh the app view"
    },
    // the callback to call when a notification includes `reload: true`,
    // will be overriden by setRefreshCallback()
    callback: () => window.location.reload(),
    // the Unix timestamp when callback() was last called
    lastCall: Date.now(),
    mostRecentMsg: 0,
    dom: {},
    // sse = the connection to /sse route
    sse: void 0,
    update(mode) {
      if (!refresh2.modeOptions[mode]) {
        console.log(`invalid refresh.mode='${mode}'`);
        return;
      }
      refresh2.mode = mode;
      refresh2.dom.select.property("value", mode);
      if (sessionStorage.getItem(refresh2.key) != mode) {
        sessionStorage.setItem(refresh2.key, mode);
      }
    },
    destroy() {
      disconnect(refresh2.sse);
      for (const k of Object.keys(refresh2.dom)) {
        if (typeof refresh2.dom[k] == "function") refresh2.dom[k].remove();
        delete refresh2.dom[k];
      }
    }
  };
  const features = JSON.parse(sessionStorage.getItem("optionalFeatures") || "{}");
  refresh2.mode = sessionStorage.getItem(refresh2.key) || features[refresh2.key] || refresh2.mode;
  sessionStorage.setItem(refresh2.key, refresh2.mode);
  const handleCls = ".sja-sse-refresh-opts-div";
  notifyDiv2.selectAll(handleCls).remove();
  const elem = notifyDiv2.insert("div", "div").attr("class", handleCls.slice(1)).style("text-align", "right");
  const s = {
    w: "32px",
    h: "24px",
    o: 0.5,
    bg: "#ececec"
  };
  const handle = elem.append("div").style("display", "inline-block").style("width", s.w).style("height", s.h).style("overflow", "hidden").style("background-color", s.bg).on("mouseover", function() {
    handle.style("width", "").style("height", "").style("opacity", "").style("background-color", "");
  }).on("mouseout", function() {
    handle.style("width", s.w).style("height", s.h).style("opacity", s.o).style("background-color", s.bg);
  });
  const dom = {
    elem,
    label: handle.append("label")
  };
  dom.label.append("span").style("font-family", "consola arial").style("font-size", "1rem").attr("title", "Click on the select input and hover over an option for details").html(`SSE refresh mode (tab-specific) <br/>`);
  dom.select = dom.label.append("select").on("change", () => {
    refresh2.mode = refresh2.dom.select.property("value");
    sessionStorage.setItem(refresh2.key, refresh2.mode);
  });
  dom.select.selectAll("option").data(Object.keys(refresh2.modeOptions)).enter().append("option").attr("value", (key) => key).attr("title", (key) => refresh2.modeOptions[key]).property("selected", (key) => key == refresh2.mode).html((key) => key);
  refresh2.dom = dom;
  return refresh2;
}
function setRefreshCallback(callback) {
  refresh.callback = callback;
}
var host = sessionStorage.getItem("hostURL") || window.testHost || "";
var sseUrl = host.endsWith("/") ? `${host}sse` : `${host}/sse`;
if (!document.hidden) setSse();
function setSse() {
  if (sse && sse == refresh.sse && sse.readyState != 2) return;
  if (refresh.sse) disconnect(refresh.sse);
  sse = new EventSource(sseUrl);
  refresh.sse = sse;
  sse.onmessage = (event) => {
    if (sse != refresh.sse) {
      disconnect(sse);
      return;
    }
    const data = JSON.parse(event.data);
    if (!data.length) return;
    handleMessageData(data, { save: true });
  };
  sse.onerror = (_) => {
    if (sse != refresh.sse) sse.close();
  };
}
function handleMessageData(_data, opts = {}) {
  if (!_data.length) return;
  const now = Date.now();
  const data = [..._data];
  if (data.length && (refresh.mode == "none" || opts.unhidden)) {
    data.unshift({
      key: "skipped refresh",
      message: "no auto-refresh",
      status: "ok",
      color: "black",
      duration: 2500,
      reload: false,
      time: Date.now()
    });
  }
  const renderedData = notify(data, now);
  if (data[0]?.key == "skipped refresh") return;
  const mostRecentMsg = Math.max(0, ...renderedData.map((d) => d.time));
  if (opts.save) localStorage.setItem(sseMessageStorageKey, JSON.stringify(data));
  if (mostRecentMsg && mostRecentMsg - refresh.lastCall > 100) {
    refresh.lastCall = refresh.mostRecentMsg ? mostRecentMsg : Math.max(mostRecentMsg, now);
    refresh.mostRecentMsg = mostRecentMsg;
    if (refresh.mode == "none") {
    } else if (refresh.mode == "appOnly") {
      console.clear();
      if (refresh.pendingCall) clearTimeout(refresh.pendingCall);
      refresh.pendingCall = setTimeout(refresh.callback, 500);
    } else if (refresh.mode == "full") {
      if (refresh.pendingCall) clearTimeout(refresh.pendingCall);
      refresh.pendingCall = setTimeout(() => window.location.reload(), 500);
    } else if (!refresh.modeOptions[refresh.mode]) {
      console.warn(`invalid value ${refresh.key}='${refresh.mode}', triggering refresh instead`);
      console.clear();
      if (refresh.pendingCall) clearTimeout(refresh.pendingCall);
      refresh.pendingCall = setTimeout(refresh.callback, 500);
    }
  }
}
function disconnect(sse2) {
  if (!sse2) return;
  if (sse2.readyState != 2) sse2.close();
  if (sse2 == refresh.sse) delete refresh.sse;
  delete sse2.onmessage;
}
document.onvisibilitychange = () => {
  if (document.hidden) {
    disconnect(refresh.sse);
  } else {
    const msg = localStorage.getItem(sseMessageStorageKey);
    const data = JSON.parse(msg || "[]");
    const opts = { unhidden: refresh.mode.endsWith("except_on_unhide") };
    if (!refresh.lastUnhide) refresh.lastUnhide = 0;
    handleMessageData(
      data.filter((m) => !m.key.includes("skipped") && m.time > refresh.lastUnhide),
      opts
    );
    if (!refresh.sse || refresh.sse.readyState === 2) {
      setSse();
    } else {
      console.warn("will reuse sse connection");
    }
  }
};
window.onstorage = (event) => {
  if (refresh.sse || document.hidden) return;
  switch (event.key) {
    case refresh.key:
      refresh.update(event.newValue);
      break;
    case sseMessageStorageKey:
      {
        const msg = localStorage.getItem(sseMessageStorageKey);
        const data = JSON.parse(msg || "[]");
        handleMessageData(data);
      }
      break;
  }
};
export {
  setRefreshCallback
};
//# sourceMappingURL=notify-2ROOBENL.js.map
