/**
 * PAGE context — patches broken menu.update.colours and removes stuck colour-dialog layers.
 */
(function () {
  if (window.__bsplusMenuColoursPatched) return;

  var MENU_UPDATE_COLOURS = "menu.update.colours";
  var SUBJECT_PREFIX = "timetable.subject.colour.";
  var TUTOR_PREFIX = "timetable.tutor.";
  var CLEANUP_FOLLOWUP_MS = 300;
  var cleanupFollowup = null;

  function isTesStyling() {
    var el = document.getElementById("logo-style");
    return el && el.textContent.indexOf("tesSeqta") !== -1;
  }

  function dismissStaleDialogs(forceColour) {
    var slide = 0;
    var panes = document.querySelectorAll(".uiSlidePane");
    for (var i = 0; i < panes.length; i++) {
      var p = panes[i];
      if (p.querySelector(".pane.colourChooser")) {
        p.remove();
        slide++;
        continue;
      }
      if (!forceColour && p.classList.contains("shown")) continue;
      if (!p.classList.contains("shown")) {
        p.remove();
        slide++;
      }
    }

    var modal = 0;
    var containers = document.querySelectorAll(".modaliser-container");
    for (var j = 0; j < containers.length; j++) {
      var c = containers[j];
      var m = c.querySelector(".modaliser");
      if (!m || !m.childElementCount || !c.classList.contains("visible")) {
        c.remove();
        modal++;
      }
    }

    document.body.classList.remove("clr-open");
    document.documentElement.classList.remove("clr-open");
    return { slideRemoved: slide, modalRemoved: modal };
  }

  function scheduleCleanup() {
    dismissStaleDialogs(true);
    if (cleanupFollowup) clearTimeout(cleanupFollowup);
    cleanupFollowup = setTimeout(function () {
      cleanupFollowup = null;
      dismissStaleDialogs(true);
    }, CLEANUP_FOLLOWUP_MS);
  }

  function applyMenuColours() {
    if (!window.user) return;
    var def = isTesStyling() ? "#2b3547" : "#dddddd";
    var items = document.querySelectorAll("#menu li[data-colour]");
    for (var i = 0; i < items.length; i++) {
      var item = items[i];
      var prefName = item.getAttribute("data-colour");
      if (!prefName) continue;
      var pref = window.user.getPreference(prefName);
      item.style.setProperty("--item-colour", (pref && pref.value) || def);
    }
  }

  function reconcileQuickbars() {
    var fixed = 0;
    var quickbars = document.querySelectorAll(".timetablepage .quickbar.visible");
    for (var i = 0; i < quickbars.length; i++) {
      var qb = quickbars[i];
      var w = qb.querySelector(".wrapper");
      if (!w || !w.childElementCount) {
        qb.classList.remove("visible");
        fixed++;
      }
    }
    if (fixed) {
      try {
        window.msg.send("calendar.quickbar.hide");
      } catch (err) {
        /* ignore */
      }
    }
    return fixed;
  }

  function findEntry(calendarId, code) {
    if (calendarId) {
      var byId = document.querySelector(
        ".timetablepage .entry[data-calendarid=\"" + calendarId + "\"]",
      );
      if (byId) return byId;
    }
    if (!code) return null;
    var entries = document.querySelectorAll(".timetablepage .entry.class");
    for (var i = 0; i < entries.length; i++) {
      var entry = entries[i];
      var titleEl = entry.querySelector(".title");
      var title =
        titleEl && titleEl.textContent ? titleEl.textContent.trim() : "";
      if (title && title.indexOf(code) !== -1) return entry;
    }
    return null;
  }

  function normalizeQuickbarContext(contents) {
    if (!contents) return contents;

    reconcileQuickbars();

    var element = contents.element;
    var calendarId =
      (element && element.getAttribute && element.getAttribute("data-calendarid")) ||
      (contents.data && contents.data.calendarid);
    var code = contents.data && contents.data.code;
    var connected =
      element &&
      element.isConnected &&
      typeof document.contains === "function" &&
      document.contains(element);

    if (!connected) {
      var replacement = findEntry(calendarId, code);
      if (replacement) contents.element = replacement;
    }

    return contents;
  }

  function isColourPref(handle) {
    return (
      typeof handle === "string" &&
      (handle.indexOf(SUBJECT_PREFIX) === 0 || handle.indexOf(TUTOR_PREFIX) === 0)
    );
  }

  function onMenuColourUpdate() {
    try {
      applyMenuColours();
    } catch (err) {
      console.error("[BetterSEQTA+] menu.update.colours failed:", err);
    }
    scheduleCleanup();
    reconcileQuickbars();
  }

  function neutralizeBrokenListeners(msg) {
    var listeners = msg.listeners && msg.listeners[MENU_UPDATE_COLOURS];
    if (!listeners) return;
    for (var i = 0; i < listeners.length; i++) {
      if (listeners[i]) listeners[i].fn = onMenuColourUpdate;
    }
  }

  function patchMsg(msg) {
    if (!msg || msg.__bsplusPatched) return;

    var send = msg.send.bind(msg);
    var register = msg.register.bind(msg);

    msg.send = function (handle, contents, suppressLogs, noRecord) {
      if (handle === MENU_UPDATE_COLOURS) {
        onMenuColourUpdate();
        return;
      }
      if (isColourPref(handle)) {
        var result = send(handle, contents, suppressLogs, noRecord);
        scheduleCleanup();
        reconcileQuickbars();
        return result;
      }
      if (handle === "calendar.quickbar.class") {
        return send(
          handle,
          normalizeQuickbarContext(contents),
          suppressLogs,
          noRecord,
        );
      }
      return send(handle, contents, suppressLogs, noRecord);
    };

    msg.register = function (handle, callback, clear, ignoreHistory) {
      if (handle === MENU_UPDATE_COLOURS) {
        return register(handle, onMenuColourUpdate, clear, ignoreHistory);
      }
      return register(handle, callback, clear, ignoreHistory);
    };

    neutralizeBrokenListeners(msg);
    msg.__bsplusPatched = true;
  }

  function tryPatch() {
    if (window.__bsplusMenuColoursPatched) return true;
    if (!window.msg || !window.msg.send) return false;
    patchMsg(window.msg);
    window.__bsplusMenuColoursPatched = true;
    return true;
  }

  if (!tryPatch()) {
    var delay = 25, waited = 0;
    (function poll() {
      if (tryPatch() || (waited += delay) >= 120000) return;
      if (window.msg) neutralizeBrokenListeners(window.msg);
      setTimeout(poll, delay = Math.min(delay * 2, 2000));
    })();
  }
})();
