"use client";

import * as React from "react";

import { useRouter } from "next/navigation";
import type { LucideIcon } from "lucide-react";

import { Badge } from "@/components/ui/badge";
import {
  Command,
  CommandDialog,
  CommandEmpty,
  CommandGroup,
  CommandInput,
  CommandItem,
  CommandList,
  CommandSeparator,
} from "@/components/ui/command";
import { buildCustomerSidebarPanelsFromNavigation, type CustomerNavigationPayload } from "@/navigation/sidebar/dynamic-sidebar";
import type { NavMainItem, SidebarPanel } from "@/navigation/sidebar/frontend-items";
import { sidebarItems } from "@/navigation/sidebar/sidebar-items";

type SearchItem = {
  group: string;
  label: string;
  url: string;
  icon?: LucideIcon;
  disabled?: boolean;
  newTab?: boolean;
};

type SearchDialogContentProps = {
  open: boolean;
  onOpenChange: (open: boolean) => void;
  /** Customer portal tenant — when set, search Transactions / Reports / Admin menus. */
  tenant?: string | null;
  navigation?: CustomerNavigationPayload | null;
  allowedRoutes?: readonly string[];
};

const MAX_QUERY_RESULTS = 40;

function flattenSidebarPanels(panels: SidebarPanel[]): SearchItem[] {
  return panels.flatMap((panel) =>
    panel.groups.flatMap((group) =>
      group.items.flatMap((item) => flattenNavItem(item, group.label ?? panel.label)),
    ),
  );
}

function flattenNavItem(item: NavMainItem, fallbackGroup: string): SearchItem[] {
  if (item.subItems?.length) {
    return item.subItems.map((sub) => ({
      group: item.title,
      label: sub.title,
      url: sub.url,
      icon: sub.icon ?? item.icon,
      disabled: sub.comingSoon,
      newTab: sub.newTab,
    }));
  }

  return [
    {
      group: fallbackGroup,
      label: item.title,
      url: item.url,
      icon: item.icon,
      disabled: item.comingSoon,
      newTab: item.newTab,
    },
  ];
}

function flattenBackendSidebarItems(): SearchItem[] {
  const groupLabels = new Set(sidebarItems.flatMap((group) => (group.label ? [group.label] : [])));

  return sidebarItems.flatMap((group) =>
    group.items.flatMap((item) => {
      if (item.subItems) {
        return item.subItems.map((sub) => ({
          group: groupLabels.has(item.title) ? (group.label ?? "Other") : item.title,
          label: sub.title,
          url: sub.url,
          icon: item.icon,
          disabled: sub.comingSoon,
          newTab: sub.newTab,
        }));
      }

      return [
        {
          group: group.label ?? "Other",
          label: item.title,
          url: item.url,
          icon: item.icon,
          disabled: item.comingSoon,
          newTab: item.newTab,
        },
      ];
    }),
  );
}

function getAvailableItems(items: SearchItem[]) {
  return items.filter((item) => !item.disabled && !item.url.includes("coming-soon"));
}

function groupBy(items: SearchItem[]) {
  const groups = new Map<string, SearchItem[]>();

  for (const item of items) {
    const groupItems = groups.get(item.group);
    if (groupItems) {
      groupItems.push(item);
    } else {
      groups.set(item.group, [item]);
    }
  }

  return Array.from(groups, ([group, groupItems]) => ({
    group,
    items: groupItems,
  }));
}

function renderGroups(items: SearchItem[], onSelect: (item: SearchItem) => void) {
  return groupBy(items).map(({ group, items: groupItems }, index) => (
    <React.Fragment key={group}>
      {index > 0 && <CommandSeparator />}
      <CommandGroup heading={group}>
        {groupItems.map((item) => (
          <CommandItem
            disabled={item.disabled}
            key={`${group}-${item.url}-${item.label}`}
            value={`${item.group} ${item.label}`}
            onSelect={() => onSelect(item)}
          >
            {item.icon ? <item.icon /> : null}
            <span>{item.label}</span>
            {item.disabled ? (
              <Badge variant="outline" className="text-xs">
                Soon
              </Badge>
            ) : null}
          </CommandItem>
        ))}
      </CommandGroup>
    </React.Fragment>
  ));
}

export function SearchDialogContent({
  open,
  onOpenChange,
  tenant = null,
  navigation = null,
  allowedRoutes,
}: SearchDialogContentProps) {
  const [query, setQuery] = React.useState("");
  const router = useRouter();

  const searchItems = React.useMemo(() => {
    if (!tenant) {
      return getAvailableItems(flattenBackendSidebarItems());
    }

    return getAvailableItems(
      flattenSidebarPanels(buildCustomerSidebarPanelsFromNavigation(tenant, navigation, allowedRoutes)),
    );
  }, [tenant, navigation, allowedRoutes]);

  const recommendations = React.useMemo(
    () => searchItems.slice(0, MAX_QUERY_RESULTS),
    [searchItems],
  );

  const visibleItems = React.useMemo(() => {
    const normalizedQuery = query.trim().toLowerCase();
    if (!normalizedQuery) return recommendations;

    return searchItems
      .filter((item) => `${item.group} ${item.label}`.toLowerCase().includes(normalizedQuery))
      .slice(0, MAX_QUERY_RESULTS);
  }, [query, recommendations, searchItems]);

  const handleOpenChange = (value: boolean) => {
    onOpenChange(value);
    if (!value) setQuery("");
  };

  const handleSelect = (item: SearchItem) => {
    if (item.disabled) return;
    handleOpenChange(false);
    if (item.newTab) {
      window.open(item.url, "_blank", "noopener,noreferrer");
    } else {
      router.push(item.url);
    }
  };

  const placeholder = tenant
    ? "Search transactions, reports, settings..."
    : "Search dashboards, users, and more...";

  return (
    <CommandDialog open={open} onOpenChange={handleOpenChange}>
      <Command shouldFilter={false}>
        <CommandInput placeholder={placeholder} value={query} onValueChange={setQuery} />
        <CommandList>
          {visibleItems.length === 0 && query.trim().length > 0 ? (
            <CommandEmpty>No results found.</CommandEmpty>
          ) : null}
          {renderGroups(visibleItems, handleSelect)}
        </CommandList>
      </Command>
    </CommandDialog>
  );
}
