import { waitForEngageMenuList } from "@/seqta/utils/waitForEngageMenuList";
import { addExtensionSettings } from "@/seqta/utils/Adders/AddExtensionSettings";
import { isSeqtaEngageExperience } from "@/seqta/utils/isSeqtaEngage";
import { loadEngageHomePage } from "@/seqta/utils/Loaders/LoadEngageHomePage";
import { loadHomePage } from "@/seqta/utils/Loaders/LoadHomePage";
import { SendNewsPage } from "@/seqta/utils/SendNewsPage";
import { attachNotificationsPanelAnimation } from "@/seqta/utils/attachNotificationsPanelAnimation";
import { setupSettingsButton } from "@/seqta/utils/setupSettingsButton";
import { waitForElm } from "@/seqta/utils/waitForElm";

import { GetThresholdOfColor } from "@/seqta/ui/colors/getThresholdColour";
import { appendBackgroundToUI } from "./ImageBackgrounds";
import stringToHTML from "@/seqta/utils/stringToHTML";
import { settingsState } from "@/seqta/utils/listeners/SettingsState";
import { updateAllColors } from "./colors/Manager";
import { delay } from "@/seqta/utils/delay";
import { LUCIDE_MOON_ICON_SVG } from "@/lib/icons/lucideMoon";
import { LUCIDE_SUN_ICON_SVG } from "@/lib/icons/lucideSun";

let cachedUserInfo: any = null;
let userInfoFetchPromise: Promise<any> | null = null;
let userInfoCacheListenersAttached = false;

export function invalidateCachedUserInfo(): void {
  cachedUserInfo = null;
  userInfoFetchPromise = null;
}

function attachUserInfoCacheInvalidation(): void {
  if (userInfoCacheListenersAttached || typeof window === "undefined") return;
  userInfoCacheListenersAttached = true;

  window.addEventListener("pageshow", (event) => {
    if (event.persisted) {
      invalidateCachedUserInfo();
    }
  });
}

attachUserInfoCacheInvalidation();

let LightDarkModeSnakeEggButton = 0;
let sidebarAccessibilityObserver: MutationObserver | null = null;
let sidebarTabOrderAnimationFrame: number | null = null;
let sidebarAccessibilityListenersAttached = false;

/** Marks menu rows that are off-screen in the drill stack (CSS blocks clicks). */
const BSPLUS_SIDEBAR_OFFSCREEN = "bsplus-sidebar-offscreen";

export async function getUserInfo(options?: { validateSession?: boolean }) {
  if (cachedUserInfo && !options?.validateSession) {
    return cachedUserInfo;
  }

  if (userInfoFetchPromise && !options?.validateSession) {
    return userInfoFetchPromise;
  }

  const fetchUserInfo = async () => {
    try {
      const response = await fetch(`${location.origin}/seqta/student/login`, {
        method: "POST",
        headers: {
          "Content-Type": "application/json; charset=utf-8",
        },
        body: JSON.stringify({
          mode: "normal",
          query: null,
          redirect_url: location.origin,
        }),
      });

      if (!response.ok) {
        throw new Error(`Failed to get user info: HTTP ${response.status}`);
      }

      const payload = (await response.json()).payload;

      if (
        cachedUserInfo &&
        options?.validateSession &&
        payload?.id != null &&
        cachedUserInfo.id != null &&
        payload.id !== cachedUserInfo.id
      ) {
        console.warn(
          "[BetterSEQTA+] Session user changed; invalidating cached user info",
        );
        invalidateCachedUserInfo();
      }

      cachedUserInfo = payload;
      return cachedUserInfo;
    } catch (error) {
      console.error("[BetterSEQTA+] Failed to get user info:", error);
      throw error;
    } finally {
      if (!options?.validateSession) {
        userInfoFetchPromise = null;
      }
    }
  };

  if (options?.validateSession) {
    return fetchUserInfo();
  }

  userInfoFetchPromise = fetchUserInfo();
  return userInfoFetchPromise;
}

export async function AddBetterSEQTAElements() {
  if (isSeqtaEngageExperience()) {
    await waitForElm("#content");
    addExtensionSettings();
    if (settingsState.onoff) {
      await injectEngageHomeButton();
    }
    void setupEngageSettingsButton();
    void addEngageUserInfo();
    return;
  }

  if (settingsState.onoff) {
    if (settingsState.DarkMode) {
      document.documentElement.classList.add("dark");
    }

    const fragment = document.createDocumentFragment();
    const menu = document.getElementById("menu")!;
    const menuList = menu.firstChild as HTMLElement;

    createHomeButton(fragment, menuList);
    createNewsButton(fragment, menu);

    menuList.insertBefore(fragment, menuList.firstChild);

    try {
      await Promise.all([appendBackgroundToUI(), handleUserInfoAndStudentData()]);
    } catch (error) {
      console.error("[BetterSEQTA+] Failed to initialize UI elements:", error);
    }

    setupEventListeners();
    await addDarkLightToggle();
    customizeMenuToggle();
    // Kept as fallback if the custom Svelte sidebar fails to mount.
    setupSidebarAccessibility();
  }

  addExtensionSettings();
  await createSettingsButton();
  setupSettingsButton();
  attachNotificationsPanelAnimation();
}

function createHomeButton(fragment: DocumentFragment, _: HTMLElement) {
  const container = document.getElementById("content")!;
  const div = document.createElement("div");
  div.classList.add("titlebar");
  container.append(div);

  fragment.appendChild(
    stringToHTML(
      /* html */ `<li class="item" data-key="home" id="homebutton" data-path="/home" data-betterseqta="true"><label><svg style="width:24px;height:24px" viewBox="0 0 24 24"><path fill="currentColor" d="M10,20V14H14V20H19V12H22L12,3L2,12H5V20H10Z" /></svg><span>Home</span></label></li>`,
    ).firstChild!,
  );
}

async function handleUserInfoAndStudentData() {
  try {
    const [userInfo, studentResponse] = await Promise.all([
      getUserInfo(),
      fetch(`${location.origin}/seqta/student/load/message/people`, {
        method: "POST",
        headers: {
          "Content-Type": "application/json; charset=utf-8",
        },
        body: JSON.stringify({ mode: "student" }),
      }),
    ]);

    updateUserInfo(userInfo);
    await updateStudentInfo((await studentResponse.json()).payload, userInfo);
  } catch (error) {
    console.error(
      "[BetterSEQTA+] Failed to handle user info and student data:",
      error,
    );
  }
}

function updateUserInfo(info: {
  basic: boolean;
  clientIP: string[] | null;
  email: string | null;
  id: number | null;
  lastAccessedTime: number | null;
  meta: {
    code: string | null;
    governmentID: string | null;
  };
  personUUID: string | null;
  status: number | null;
  synergeticCommunityUrl: string | null;
  type: string | null;
  userCode: string | null;
  userDesc: string | null;
  userName: string | null;
}) {
  const titlebar = document.getElementsByClassName("titlebar")[0];
  const metadata = [info.meta.code, info.meta.governmentID]
    .filter((value): value is string => Boolean(value))
    .join(" // ");
  const displayName = info.userDesc || info.userName || "";

  titlebar.append(
    stringToHTML(/* html */ `
      <div class="userInfosvgdiv tooltip">
        <svg class="userInfosvg" viewBox="0 0 24 24"><path fill="var(--text-primary)" d="M12,19.2C9.5,19.2 7.29,17.92 6,16C6.03,14 10,12.9 12,12.9C14,12.9 17.97,14 18,16C16.71,17.92 14.5,19.2 12,19.2M12,5A3,3 0 0,1 15,8A3,3 0 0,1 12,11A3,3 0 0,1 9,8A3,3 0 0,1 12,5M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12C22,6.47 17.5,2 12,2Z"></path></svg>
        <div class="tooltiptext topmenutooltip" id="logouttooltip"></div>
      </div>
    `).firstChild!,
  );

  titlebar.append(
    stringToHTML(/* html */ `
      <div class="userInfo">
        <div class="userInfoText">
          <div style="display: flex; align-items: center;">
            <p class="userInfohouse userInfoCode" style="display: none;"></p>
            ${displayName ? `<p class="userInfoName">${displayName}</p>` : ""}
          </div>
          ${metadata ? `<p class="userInfoCode">${metadata}</p>` : ""}
        </div>
      </div>
    `).firstChild!,
  );

  document
    .getElementById("logouttooltip")!
    .appendChild(document.getElementsByClassName("logout")[0]);
}

async function updateStudentInfo(students: any, info: Awaited<ReturnType<typeof getUserInfo>>) {
  const index = students.findIndex(
    (person: any) =>
      person.firstname == info.userDesc.split(" ")[0] &&
      person.surname == info.userDesc.split(" ")[1],
  );

  const houseelement = document.getElementsByClassName(
    "userInfohouse",
  )[0] as HTMLElement | undefined;

  if (!houseelement) return;

  const student = students[index] ?? {};
  let text = "";

  if (student.house) {
    text = `${student.year ?? ""}${student.house}`;

    if (student.house_colour) {
      houseelement.style.background = student.house_colour;
      try {
        const colorresult = GetThresholdOfColor(student.house_colour);
        houseelement.style.color =
          colorresult && colorresult > 300 ? "black" : "white";
      } catch {
        // Invalid color format, leave text color as default
      }
    }
  } else if (student.year) {
    text = student.year;
  }

  houseelement.innerText = text;
  houseelement.style.display = text ? "block" : "none";
}

function createNewsButton(fragment: DocumentFragment, menu: HTMLElement) {
  fragment.appendChild(
    stringToHTML(
      '<li class="item" data-key="news" id="newsbutton" data-path="/news" data-betterseqta="true"><label><svg style="width:24px;height:24px" viewBox="0 0 24 24"><path fill="currentColor" d="M20 3H4C2.89 3 2 3.89 2 5V19C2 20.11 2.89 21 4 21H20C21.11 21 22 20.11 22 19V5C22 3.89 21.11 3 20 3M5 7H10V13H5V7M19 17H5V15H19V17M19 13H12V11H19V13M19 9H12V7H19V9Z" /></svg><span>News</span></label></li>',
    ).firstChild!,
  );

  const iconCover = document.createElement("div");
  iconCover.classList.add("icon-cover");
  iconCover.id = "icon-cover";
  menu.appendChild(iconCover);
}

function setupEventListeners() {
  const menuCover = document.querySelector("#icon-cover");
  const homebutton = document.getElementById("homebutton");
  const newsbutton = document.getElementById("newsbutton");

  const activateMenuAction = (button: HTMLElement, action: () => void) => {
    if (
      button.classList.contains("draggable") ||
      button.classList.contains("active")
    ) {
      return;
    }

    action();
  };

  homebutton?.addEventListener("click", function () {
    activateMenuAction(homebutton, () => {
      loadHomePage();
    });
  });

  newsbutton?.addEventListener("click", function () {
    activateMenuAction(newsbutton, () => {
      SendNewsPage();
    });
  });

  menuCover?.addEventListener("click", function () {
    location.href = "../#?page=/home";
    loadHomePage();
    (
      document.getElementById("menu")!.firstChild! as HTMLElement
    ).classList.remove("noscroll");
  });
}

async function createSettingsButton(parent?: Element) {
  if (document.getElementById("AddedSettings")) return;

  const target =
    parent ??
    document.getElementById("content") ??
    document.getElementById("container") ??
    document.body;
  target.append(
    stringToHTML(/* html */ `
      <button class="addedButton tooltip" id="AddedSettings">
        <svg width="24" height="24" viewBox="0 0 24 24">
          <g><g><path d="M23.182,6.923c-.29,0-3.662,2.122-4.142,2.4l-2.8-1.555V4.511l4.257-2.456a.518.518,0,0,0,.233-.408.479.479,0,0,0-.233-.407,6.511,6.511,0,1,0-3.327,12.107,6.582,6.582,0,0,0,6.148-4.374,5.228,5.228,0,0,0,.333-1.542A.461.461,0,0,0,23.182,6.923Z"></path><path d="M9.73,10.418,7.376,12.883c-.01.01-.021.016-.03.025L1.158,19.1a2.682,2.682,0,1,0,3.793,3.793l4.583-4.582,0,0,4.1-4.005-.037-.037A9.094,9.094,0,0,1,9.73,10.418ZM3.053,21.888A.894.894,0,1,1,3.946,21,.893.893,0,0,1,3.053,21.888Z"></path></g></g>
        </svg>
        ${settingsState.onoff ? '<div class="tooltiptext topmenutooltip">BetterSEQTA+ Settings</div>' : ""}
      </button>
    `).firstChild!,
  );
}

async function injectEngageHomeButton() {
  if (document.getElementById("homebutton")) return;

  const menuList = await waitForEngageMenuList();
  if (!menuList || document.getElementById("homebutton")) return;

  const li = stringToHTML(
    /* html */ `<li class="item" data-key="home" id="homebutton" data-path="/home" data-betterseqta="true"><label><svg style="width:24px;height:24px" viewBox="0 0 24 24"><path fill="currentColor" d="M10,20V14H14V20H19V12H22L12,3L2,12H5V20H10Z" /></svg><span>Home</span></label></li>`,
  ).firstChild as HTMLElement;
  menuList.insertBefore(li, menuList.firstElementChild);

  document.getElementById("homebutton")?.addEventListener("click", () => {
    const btn = document.getElementById("homebutton") as HTMLElement;
    if (
      btn.classList.contains("draggable") ||
      btn.classList.contains("active")
    ) {
      return;
    }
    window.location.replace(`${location.origin}/#?page=/home`);
    void loadEngageHomePage();
  });
}

async function getEngageUserInfo() {
  const response = await fetch(`${location.origin}/seqta/parent/login`, {
    method: "POST",
    headers: { "Content-Type": "application/json; charset=utf-8" },
    body: JSON.stringify({
      mode: "normal",
      query: null,
      redirect_url: location.origin + "/",
    }),
  });
  return (await response.json()).payload as {
    userDesc: string | null;
    userName: string | null;
    userCode: string | null;
    email: string | null;
    type: string | null;
  };
}

async function addEngageUserInfo() {
  const content = await waitForElm("#content") as HTMLElement;

  let info: Awaited<ReturnType<typeof getEngageUserInfo>>;
  try {
    info = await getEngageUserInfo();
  } catch (error) {
    console.error("[BetterSEQTA+] Failed to get Engage user info:", error);
    return;
  }

  const displayName = info.userDesc || info.userName || "";
  const subText = info.userCode || info.email || "";

  const titlebar = document.createElement("div");
  titlebar.classList.add("titlebar", "engage-titlebar");

  titlebar.append(
    stringToHTML(/* html */ `
      <div class="userInfo">
        <div class="userInfoText">
          ${displayName ? `<p class="userInfoName">${displayName}</p>` : ""}
          ${subText ? `<p class="userInfoCode">${subText}</p>` : ""}
        </div>
      </div>
    `).firstChild!,
  );

  const iconNode = stringToHTML(/* html */ `
    <div class="userInfosvgdiv tooltip" id="engage-logouttooltip-wrap">
      <svg class="userInfosvg" viewBox="0 0 24 24"><path fill="var(--text-primary)" d="M12,19.2C9.5,19.2 7.29,17.92 6,16C6.03,14 10,12.9 12,12.9C14,12.9 17.97,14 18,16C16.71,17.92 14.5,19.2 12,19.2M12,5A3,3 0 0,1 15,8A3,3 0 0,1 12,11A3,3 0 0,1 9,8A3,3 0 0,1 12,5M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12C22,6.47 17.5,2 12,2Z"></path></svg>
      <div class="tooltiptext topmenutooltip" id="engage-logouttooltip">
        <button class="logout engage-logout">
          <svg style="width:20px;height:20px;vertical-align:middle;" viewBox="0 0 24 24"><path fill="currentColor" d="M17 7L15.59 8.41L18.17 11H8V13H18.17L15.59 15.58L17 17L22 12M4 5H12V3H4C2.9 3 2 3.9 2 5V19C2 20.1 2.9 21 4 21H12V19H4V5Z"/></svg>
        </button>
      </div>
    </div>
  `).firstChild!;

  titlebar.append(iconNode);
  content.appendChild(titlebar);

  titlebar.querySelector<HTMLElement>(".engage-logout")?.addEventListener("click", async () => {
    await fetch(`${location.origin}/seqta/parent/logout`, { method: "POST" });
    location.reload();
  });
}

async function mountEngageToolbarControls(parent?: Element) {
  // React can remount the notifications chrome — recreate missing controls.
  if (!document.getElementById("LightDarkModeButton")) {
    await addDarkLightToggle(parent);
  }
  if (!document.getElementById("AddedSettings")) {
    await createSettingsButton(parent);
  }
  setupSettingsButton();
  attachNotificationsPanelAnimation();
}

async function setupEngageSettingsButton() {
  let mounting = false;

  const tryMount = async () => {
    if (mounting || document.getElementById("AddedSettings")) return;
    mounting = true;
    try {
      try {
        const notificationsWrapper = await waitForElm(
          "#content > div.connectedNotificationsWrapper > div",
          true,
          100,
          40,
        );
        const parent = notificationsWrapper.parentElement!;
        await mountEngageToolbarControls(parent);
      } catch {
        await mountEngageToolbarControls();
      }
    } finally {
      mounting = false;
    }
  };

  await tryMount();

  // Re-inject if Engage's React shell wipes the toolbar controls.
  const content = document.getElementById("content");
  if (!content || (content as HTMLElement).dataset.bsplusEngageSettingsWatch === "1") {
    return;
  }
  (content as HTMLElement).dataset.bsplusEngageSettingsWatch = "1";

  const observer = new MutationObserver(() => {
    if (document.getElementById("AddedSettings")) return;
    void tryMount();
  });
  observer.observe(content, { childList: true, subtree: true });
}

function GetLightDarkModeString() {
  return settingsState.DarkMode
    ? "Switch to light theme"
    : "Switch to dark theme";
}

async function addDarkLightToggle(parent?: Element) {
  const toggleTarget = parent ?? document.getElementById("content")!;
  toggleTarget.append(
    stringToHTML(/* html */ `
      <button class="addedButton DarkLightButton tooltip" id="LightDarkModeButton">
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">${settingsState.DarkMode ? LUCIDE_SUN_ICON_SVG : LUCIDE_MOON_ICON_SVG}</svg>
        <div class="tooltiptext topmenutooltip" id="darklighttooliptext">${GetLightDarkModeString()}</div>
      </button>
    `).firstChild!,
  );

  updateAllColors();

  const lightDarkModeButtonElement = document.getElementById(
    "LightDarkModeButton",
  )!;

  lightDarkModeButtonElement.addEventListener("click", async () => {
    const darklightText = document.getElementById("darklighttooliptext");

    LightDarkModeSnakeEggButton += 1;

    if (LightDarkModeSnakeEggButton >= 10) {
      window.open("https://www.youtube.com/watch?v=dQw4w9WgXcQ", "_blank");
      LightDarkModeSnakeEggButton = 0;
    }

    if (
      settingsState.originalDarkMode !== undefined &&
      settingsState.selectedTheme
    ) {
      darklightText!.innerText = "Locked by current theme";
      await delay(1000);
      darklightText!.innerText = GetLightDarkModeString();
      return;
    }

    settingsState.DarkMode = !settingsState.DarkMode;
    updateAllColors();

    const svgElement = lightDarkModeButtonElement.querySelector("svg")!;
    svgElement.innerHTML = settingsState.DarkMode
      ? LUCIDE_SUN_ICON_SVG
      : LUCIDE_MOON_ICON_SVG;
    darklightText!.innerText = GetLightDarkModeString();
  });
}

function customizeMenuToggle() {
  const menuToggle = document.getElementById("menuToggle")!;
  menuToggle.innerHTML = "";

  for (let i = 0; i < 3; i++) {
    const line = document.createElement("div");
    line.className = "hamburger-line";
    menuToggle.appendChild(line);
  }
}

function setupSidebarAccessibility() {
  updateSidebarAccessibility();

  const menu = document.getElementById("menu");
  if (!menu) return;

  sidebarAccessibilityObserver?.disconnect();
  sidebarAccessibilityObserver = new MutationObserver((mutations) => {
    // Custom Svelte sidebar owns drill a11y — ignore its DOM (opening Goals/Folios
    // mutates a lot; re-running here used to help freeze the tab).
    if (menu.classList.contains("bsplus-custom-sidebar")) {
      const root = document.getElementById("bsplus-sidebar-root");
      if (
        root &&
        mutations.every(
          (m) => root === m.target || root.contains(m.target as Node),
        )
      ) {
        return;
      }
      // Still ignore class/style-only native noise while custom sidebar is on.
      if (
        mutations.every(
          (m) =>
            m.type === "attributes" &&
            (m.attributeName === "class" || m.attributeName === "style"),
        )
      ) {
        return;
      }
    }
    scheduleSidebarAccessibilityUpdate();
  });
  sidebarAccessibilityObserver.observe(menu, {
    subtree: true,
    childList: true,
    attributes: true,
    attributeFilter: ["class", "style"],
  });

  if (!sidebarAccessibilityListenersAttached) {
    document.addEventListener("keydown", handleSidebarKeyboardActivation);
    sidebarAccessibilityListenersAttached = true;
  }
}

function scheduleSidebarAccessibilityUpdate() {
  if (sidebarTabOrderAnimationFrame !== null) {
    cancelAnimationFrame(sidebarTabOrderAnimationFrame);
  }

  // Double rAF: SEQTA applies drill state on the next frame after click.
  sidebarTabOrderAnimationFrame = requestAnimationFrame(() => {
    requestAnimationFrame(() => {
      sidebarTabOrderAnimationFrame = null;
      updateSidebarAccessibility();
    });
  });
}

function handleSidebarKeyboardActivation(event: KeyboardEvent) {
  const target = event.target;
  if (!(target instanceof HTMLElement)) return;

  const menuItem = target.closest("#menu li, #menu section") as
    | HTMLElement
    | null;
  if (!menuItem) return;

  if (event.key === "Tab") {
    if (target !== menuItem) return;
    const menu = document.getElementById("menu");
    if (!menu) return;

    const visibleList = getVisibleSidebarList(menu);
    if (!visibleList) return;

    const visibleEntries = getDirectSidebarEntries(visibleList);
    if (visibleEntries.length === 0) return;

    const boundaryEntry = event.shiftKey
      ? visibleEntries[0]
      : visibleEntries[visibleEntries.length - 1];

    if (boundaryEntry !== menuItem) return;

    const parentEntry = getSidebarListParentEntry(visibleList);
    if (!parentEntry) return;

    event.preventDefault();
    parentEntry.classList.remove("active");
    scheduleSidebarAccessibilityUpdate();
    requestAnimationFrame(() => {
      parentEntry.focus();
    });
    return;
  }

  if (event.key !== "Enter" && event.key !== " ") return;

  event.preventDefault();

  const childSubmenu = menuItem.querySelector(":scope > .sub > ul") as
    | HTMLElement
    | null;

  menuItem.click();
  scheduleSidebarAccessibilityUpdate();

  if (childSubmenu) {
    focusFirstSidebarSubmenuEntry(menuItem);
  }
}

/** Folder rows on the path to the currently open sidebar list. */
function getDrillFolderChain(
  menu: HTMLElement,
  visibleList: HTMLElement | null,
): Set<HTMLElement> {
  const chain = new Set<HTMLElement>();
  let list: HTMLElement | null = visibleList;

  while (list && menu.contains(list)) {
    const folder = getSidebarListParentEntry(list);
    if (!folder || !menu.contains(folder)) break;
    chain.add(folder);

    const containerUl = folder.parentElement;
    if (!(containerUl instanceof HTMLElement)) break;
    const parentSub = containerUl.closest(".sub");
    if (!parentSub || !menu.contains(parentSub)) break;
    const parentFolder = parentSub.parentElement;
    if (!(parentFolder instanceof HTMLElement) || !menu.contains(parentFolder)) {
      break;
    }
    chain.add(parentFolder);
    list =
      parentFolder.parentElement instanceof HTMLElement
        ? parentFolder.parentElement
        : null;
  }

  return chain;
}

function isSidebarEditMode(): boolean {
  const menu = document.getElementById("menu");
  return (
    document.querySelector(".editmenuoption-container") != null ||
    menu?.classList.contains("bsplus-sidebar-edit-mode") === true
  );
}

function clearSidebarAccessibilityLocks() {
  const menu = document.getElementById("menu");
  if (!menu) return;

  const entries = menu.querySelectorAll("li, section");
  for (const entry of entries) {
    if (!(entry instanceof HTMLElement)) continue;
    entry.classList.remove(BSPLUS_SIDEBAR_OFFSCREEN);
  }
}

function updateSidebarAccessibility() {
  if (isSidebarEditMode()) {
    clearSidebarAccessibilityLocks();
    return;
  }

  const menu = document.getElementById("menu");
  if (!menu) return;

  // Custom Svelte sidebar owns its own a11y / drill UI — do not mark its
  // `#bsplus-sidebar-root` items offscreen based on the hidden native list.
  if (menu.classList.contains("bsplus-custom-sidebar")) {
    const root = document.getElementById("bsplus-sidebar-root");
    if (root) {
      for (const entry of root.querySelectorAll(`.${BSPLUS_SIDEBAR_OFFSCREEN}`)) {
        if (entry instanceof HTMLElement) {
          entry.classList.remove(BSPLUS_SIDEBAR_OFFSCREEN);
        }
      }
    }
    return;
  }

  const visibleList = getVisibleSidebarList(menu);
  const visibleEntries = new Set(
    visibleList ? getDirectSidebarEntries(visibleList) : [],
  );
  const drillFolders = getDrillFolderChain(menu, visibleList);
  const menuEntries = menu.querySelectorAll("li.item, section.item, li, section");

  for (const entry of menuEntries) {
    if (!(entry instanceof HTMLElement)) continue;

    const label = entry.querySelector(":scope > label") as HTMLLabelElement | null;
    if (!label) continue;

    const interactive =
      visibleEntries.has(entry) || drillFolders.has(entry);

    if (!interactive) {
      entry.classList.add(BSPLUS_SIDEBAR_OFFSCREEN);
      entry.tabIndex = -1;
      label.tabIndex = -1;
      continue;
    }

    entry.classList.remove(BSPLUS_SIDEBAR_OFFSCREEN);
    entry.tabIndex = 0;
    label.tabIndex = -1;

    if (!entry.hasAttribute("role")) {
      entry.setAttribute("role", "button");
    }

    const accessibleLabel = label.textContent?.trim();
    if (accessibleLabel) {
      entry.setAttribute("aria-label", accessibleLabel);
    }
  }
}

function getDirectSidebarEntries(list: HTMLElement) {
  return Array.from(list.querySelectorAll(":scope > li, :scope > section")).filter(
    (entry): entry is HTMLElement => entry instanceof HTMLElement,
  );
}

function getVisibleSidebarList(menu: HTMLElement) {
  let currentList = menu.querySelector(
    ":scope > ul:not(#bsplus-sidebar-root)",
  ) as HTMLElement | null;

  while (currentList) {
    const activeSubmenuParent = currentList.querySelector(
      ":scope > li.hasChildren.active, :scope > section.hasChildren.active",
    ) as HTMLElement | null;

    if (!activeSubmenuParent) {
      return currentList;
    }

    const nextList = activeSubmenuParent.querySelector(
      ":scope > .sub > ul",
    ) as HTMLElement | null;

    if (!nextList) {
      return currentList;
    }

    currentList = nextList;
  }

  return null;
}

function getSidebarListParentEntry(list: HTMLElement) {
  const sub = list.closest(".sub");
  return sub?.parentElement instanceof HTMLElement ? sub.parentElement : null;
}

function focusFirstSidebarSubmenuEntry(parentEntry: HTMLElement) {
  const menu = document.getElementById("menu");
  if (!menu) return;

  requestAnimationFrame(() => {
    requestAnimationFrame(() => {
      if (!parentEntry.classList.contains("active")) return;

      const visibleList = getVisibleSidebarList(menu);
      if (!visibleList || getSidebarListParentEntry(visibleList) !== parentEntry) {
        return;
      }

      const firstEntry = getDirectSidebarEntries(visibleList).find(
        (entry) =>
          entry.offsetParent !== null &&
          window.getComputedStyle(entry).display !== "none",
      );

      firstEntry?.focus({ preventScroll: true });
    });
  });
}
