import {
  defineRouteMiddleware,
  type StarlightRouteData,
} from "@astrojs/starlight/route-data";
import { AstroError } from "astro/errors";
import config from "virtual:starlight-utils/config";

export const onRequest = defineRouteMiddleware((context) => {
  // Initialize object
  context.locals.starlightUtils = {};

  // Logic for navLinks
  if (config?.navLinks?.leading) {
    const sidebarLabel = config?.navLinks?.leading?.useSidebarLabelled;

    if (!sidebarLabel) {
      throw new AstroError(
        `No sidebar label was specified for the ${JSON.stringify(config?.navLinks?.leading)} entry in the Astro config.`
      );
    }

    const starlightRouteSidebar = context.locals.starlightRoute.sidebar;
    const navLinks: typeof starlightRouteSidebar = [];
    const filteredSidebar: typeof starlightRouteSidebar = [];

    starlightRouteSidebar.forEach((entry) => {
      const condition =
        entry.label === config?.navLinks?.leading?.useSidebarLabelled;
      condition ? navLinks.push(entry) : filteredSidebar.push(entry);
    });

    if (navLinks.length != 1 || !navLinks[0]) {
      throw new AstroError(
        `Could not find the sidebar labelled \`${sidebarLabel}\` that was referenced in the Starlight Utils config.`
      );
    }

    if (navLinks[0].type !== "group") {
      throw new AstroError(
        `\`${navLinks[0].label}\` cannot be used with multi-sidebar.
    
      The sidebar entry specified in the Astro config must be either a group or autogenerated.
    
      See https://starlight.astro.build/guides/sidebar/#groups and https://starlight.astro.build/guides/sidebar/#autogenerated-groups for more details.`
      );
    }

    if (navLinks[0].entries.some((entry) => entry.type !== "link")) {
      throw new AstroError(
        `Only links can be specified for nav links. No groups or autogenerated types are allowed.`
      );
    }

    // Set navLinks value
    context.locals.starlightUtils.navLinks = [...navLinks[0].entries];
    // Set the filtered sidebar
    context.locals.starlightRoute.sidebar = filteredSidebar;
  }

  // Logic for multi-sidebar
  if (config?.multiSidebar) {
    // All entries must be group types
    const data = context.locals.starlightRoute.sidebar.map((entry) => {
      if (entry.type != "group") {
        throw new AstroError(
          `\`${entry.label}\` cannot be used with multi-sidebar.
  
    Each top-level \`sidebar\` item in the Starlight config must be either a group or autogenerated.
  
    See https://starlight.astro.build/guides/sidebar/#groups and https://starlight.astro.build/guides/sidebar/#autogenerated-groups for more details.`
        );
      }

      // Recursively check if a group of sidebar entries contains the current page
      const findIfIsCurrent = (
        entry: StarlightRouteData["sidebar"][number]
      ): boolean => {
        if (entry.type === "link") {
          return entry.isCurrent;
        }
        return entry.entries.some((item) => findIfIsCurrent(item));
      };

      const isCurrentSidebar = findIfIsCurrent(entry);

      return {
        isCurrentSidebar,
        sidebar: [...entry.entries],
        label: entry,
      };
    });
    // If the current page being built isn't contained in a sidebar, then render the first sidebar
    if (data[0] && !data.some(({ isCurrentSidebar }) => isCurrentSidebar)) {
      data[0].isCurrentSidebar = true;
    }
    context.locals.starlightUtils.multiSidebar = data;
  }
});
