import type { NavItem } from "@/constants/sidebar-menu";

import type { SearchGroup, SearchResult } from "./service/search-service";

// Which sidebar entry can host each kind of hit. A group is only shown when
// the reader has one of these pages in their own menu, so the search never
// offers a page they cannot open.
const GROUP_MENU_MATCHERS: Record<SearchGroup, string[]> = {
  issues: ["/issue-matrix", "/cdc-issue-matrix", "/cefp-issue-matrix", "/wg-issues"],
  progressReports: ["/progress-reports", "/progress-report"],
  meetings: ["/meeting-requests", "/meeting-summary"],
  plenary: ["/plenary/plenaries", "/plenary/rgc-decisions", "/rgc-decision"],
};

// Not every section that lists a kind of record also has a page for a single
// one. These follow the routes under `app/`, so update them when a detail page
// is added.
const MEETING_REQUEST_DETAIL_SECTIONS = ["/ministry"];
const RGC_DECISION_DETAIL_SECTIONS = ["/cdc", "/cefp"];

function hasDetailPage(menuUrl: string, sections: string[]) {
  return sections.some((section) => menuUrl.startsWith(`${section}/`));
}

// The sidebar nests one level, so both levels are searched for a match.
function flattenNavItems(items: NavItem[]): NavItem[] {
  return items.flatMap((item) => [item, ...flattenNavItems(item.items ?? [])]);
}

function findMenuUrl(
  navItems: NavItem[],
  candidates: string[],
): string | null {
  const urls = flattenNavItems(navItems)
    .map((item) => item.url)
    .filter(Boolean);

  for (const candidate of candidates) {
    const match = urls.find((url) => url.endsWith(candidate));

    if (match) return match;
  }

  return null;
}

// The page a hit opens, taken from the reader's own menu. Null means their
// menu has no page for it, so the hit is left out of the dropdown.
export function getSearchResultHref(
  result: SearchResult,
  navItems: NavItem[],
): string | null {
  const meta = result.meta ?? {};

  if (result.group === "meetings") {
    // Summaries and requests are two different menu entries.
    if (meta.meetingSummaryId) {
      const menuUrl = findMenuUrl(navItems, ["/meeting-summary"]);

      return menuUrl ? `${menuUrl}/${result.id}` : null;
    }

    const menuUrl = findMenuUrl(navItems, ["/meeting-requests"]);

    if (!menuUrl) return null;

    // Only the Ministry section has a page for one meeting request; the other
    // sections stop at the list, so that is where the hit goes.
    return hasDetailPage(menuUrl, MEETING_REQUEST_DETAIL_SECTIONS)
      ? `${menuUrl}/${result.id}`
      : menuUrl;
  }

  if (result.group === "plenary") {
    if (meta.rgcDecisionId) {
      const menuUrl = findMenuUrl(navItems, [
        "/plenary/rgc-decisions",
        "/rgc-decision",
      ]);

      if (!menuUrl) return null;

      // CDC and CEFP can open one decision; the other sections only have the
      // list.
      return hasDetailPage(menuUrl, RGC_DECISION_DETAIL_SECTIONS)
        ? `${menuUrl}/${result.id}`
        : menuUrl;
    }

    const menuUrl = findMenuUrl(navItems, ["/plenary/plenaries"]);

    return menuUrl ? `${menuUrl}/${result.id}` : null;
  }

  const menuUrl = findMenuUrl(navItems, GROUP_MENU_MATCHERS[result.group]);

  return menuUrl ? `${menuUrl}/${result.id}` : null;
}
