"use client";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import { cn } from "@/lib/utils";
import Link from "next/link";
import { usePathname, useRouter } from "next/navigation";
import {
  type HTMLAttributes,
  type ReactNode,
  useCallback,
  useEffect,
  useMemo,
  useRef,
  useState,
} from "react";
import { PiGraph } from "react-icons/pi";
import { PlugIcon } from "lucide-react";

// sessionStorage utilities for managing user's connection type preference
// Using sessionStorage instead of localStorage so preference is tab-specific
// and doesn't persist across new tabs or browser sessions
const STORAGE_KEY = "copilotkit-nav-preference";
const DEFAULT_URL = "/";

function getStoredNavPreference(): string | null {
  if (typeof window === "undefined") return null;
  try {
    return sessionStorage.getItem(STORAGE_KEY);
  } catch {
    return null;
  }
}

function setStoredNavPreference(url: string): void {
  if (typeof window === "undefined") return;
  try {
    sessionStorage.setItem(STORAGE_KEY, url);
  } catch {
    // Ignore sessionStorage errors
  }
}

// Utility function to handle navigation scrolling
function handleNavigationScroll(fromPath: string, toPath: string) {
  // Check if this is an integration switch (different top-level path)
  const fromIntegration = fromPath.split("/")[1];
  const toIntegration = toPath.split("/")[1];
  const isIntegrationSwitch =
    fromIntegration !== toIntegration && toPath !== "/";

  // For both integration switches and internal navigation, scroll the main page to top
  setTimeout(() => {
    window.scrollTo({ top: 0, behavior: "auto" });
  }, 100);
}

// Utility function to scroll sidebar to selected item
function scrollSidebarToSelectedItem(targetPath?: string) {
  setTimeout(() => {
    const normalize = (p?: string) => {
      if (!p) return "";
      try {
        // Ensure we compare pathname only, strip query/hash and trailing slash
        const url = p.startsWith("http")
          ? new URL(p)
          : new URL(p, window.location.origin);
        let path = url.pathname;
        if (path.length > 1 && path.endsWith("/")) path = path.slice(0, -1);
        return path;
      } catch {
        // Fallback for relative like ./generative-ui
        let path = p.split("?")[0].split("#")[0];
        if (path.startsWith("./")) path = path.slice(1);
        if (!path.startsWith("/")) {
          // Resolve against current path
          const base = window.location.pathname.replace(/\/$/, "");
          path = `${base}/${path}`.replace(/\/+/g, "/");
        }
        if (path.length > 1 && path.endsWith("/")) path = path.slice(0, -1);
        return path;
      }
    };

    const target = normalize(targetPath || window.location.pathname);

    // Gather all anchors and find best match
    const anchors = Array.from(
      document.querySelectorAll("a[href]"),
    ) as HTMLAnchorElement[];
    const candidates = anchors.filter((a) => {
      const hrefNorm = normalize(a.href);
      return (
        hrefNorm === target ||
        hrefNorm === `${target}/` ||
        hrefNorm.endsWith(target) ||
        hrefNorm.endsWith(`${target}/`)
      );
    });

    let selectedEl: HTMLElement | null = null;

    if (candidates.length > 0) {
      // Prefer the one closest to the left (likely the sidebar)
      candidates.sort(
        (a, b) =>
          a.getBoundingClientRect().left - b.getBoundingClientRect().left,
      );
      selectedEl = candidates[0];
    }

    // Fallbacks based on aria-current or data attributes
    if (!selectedEl) {
      selectedEl = (document.querySelector('a[aria-current="page"]') ||
        document.querySelector('[data-active="true"]')) as HTMLElement | null;
    }

    if (!selectedEl) return;

    // Find nearest scrollable ancestor
    function getScrollableAncestor(el: HTMLElement | null): HTMLElement | null {
      let node: HTMLElement | null = el;
      while (node && node !== document.body) {
        const style = window.getComputedStyle(node);
        const overflowY = style.overflowY;
        const canScroll =
          (overflowY === "auto" || overflowY === "scroll") &&
          node.scrollHeight > node.clientHeight;
        if (canScroll) return node;
        node = node.parentElement as HTMLElement | null;
      }
      return null;
    }

    const container =
      getScrollableAncestor(selectedEl) ||
      (document.querySelector("aside, nav") as HTMLElement | null);

    if (container) {
      const containerRect = container.getBoundingClientRect();
      const elRect = selectedEl.getBoundingClientRect();

      const currentScrollTop = container.scrollTop;
      const offsetTop = elRect.top - containerRect.top + currentScrollTop;
      const targetScrollTop = Math.max(
        0,
        offsetTop - container.clientHeight / 2 + selectedEl.offsetHeight / 2,
      );

      container.scrollTo({ top: targetScrollTop, behavior: "smooth" });
    } else if ("scrollIntoView" in selectedEl) {
      selectedEl.scrollIntoView({
        behavior: "smooth",
        block: "center",
        inline: "nearest",
      });
    }
  }, 350); // allow DOM/route transition
}

// Global navigation handler for use with any link
export function useNavigationScroll() {
  const pathname = usePathname();

  return (toPath: string) => {
    handleNavigationScroll(pathname, toPath);
    scrollSidebarToSelectedItem(toPath);
  };
}

// Custom Link component for MDX content with navigation scrolling
export function NavigationLink({
  href,
  children,
  className,
  ...props
}: {
  href: string;
  children: React.ReactNode;
  className?: string;
  [key: string]: any;
}) {
  const handleScroll = useNavigationScroll();
  const pathname = usePathname();

  // Convert absolute links that point within the same integration to relative
  const normalizeHref = (input: string): string => {
    if (!input || typeof input !== "string") return input;
    if (!input.startsWith("/")) return input; // already relative or external

    const currentSplit = pathname.split("/").filter((x) => x);
    const targetSplit = input.split("/").filter((x) => x);
    while (
      currentSplit.length > 1 &&
      targetSplit.length > 1 &&
      currentSplit[0] === targetSplit[0]
    ) {
      currentSplit.shift();
      targetSplit.shift();
    }

    let rel = "";
    for (let i = 0; i < currentSplit.length - 1; i++) {
      rel += "../";
    }
    if (rel === "") {
      rel = "./";
    }
    rel += targetSplit.join("/");
    return rel;
  };

  const renderedHref = normalizeHref(href);

  return (
    <Link
      href={renderedHref}
      onClick={() => {
        // Use absolute path for scroll logic
        const absoluteTarget = href;
        handleScroll(absoluteTarget);
      }}
      className={className}
      {...props}
    >
      {children}
    </Link>
  );
}

export function isActive(
  url: string,
  pathname: string,
  nested = true,
  root = false,
): boolean {
  // Exact match
  if (url === pathname) return true;

  // For nested matching
  if (nested) {
    // Special handling for root URL
    if (root && url === "/") {
      return pathname === "/";
    }

    // For non-root URLs, check if pathname starts with the URL followed by a slash
    // This ensures /direct-to-llm/guides/quickstart matches /direct-to-llm/guides/frontend-actions
    if (url !== "/" && pathname.startsWith(`${url}/`)) {
      return true;
    }

    // Special case for direct-to-llm: if the option URL is /direct-to-llm/guides/quickstart
    // and the current path is anywhere under /direct-to-llm/, consider it active
    if (
      url.includes("/direct-to-llm/") &&
      pathname.startsWith("/direct-to-llm/")
    ) {
      return true;
    }
  }

  return false;
}

export interface Option {
  /**
   * Redirect URL of the folder, usually the index page
   */
  url?: string;
  /**
   * External link URL
   */
  href?: string;
  icon?: ReactNode;
  title: ReactNode;
  description?: ReactNode;
  bgGradient: string;
  selectedStyle?: string;
  props?: HTMLAttributes<HTMLElement>;
}

export interface OptionDropdown {
  title: ReactNode;
  options: Option[];
}

export interface Separator {
  type: "separator";
}

export interface Label {
  type: "label";
  text: string;
}

function isOptionDropdown(
  item: Option | OptionDropdown | Separator | Label,
): item is OptionDropdown {
  return "options" in item;
}

function isOption(
  item: Option | OptionDropdown | Separator | Label,
): item is Option {
  return !isOptionDropdown(item) && !isSeparator(item) && !isLabel(item);
}

function isSeparator(
  item: Option | OptionDropdown | Separator | Label,
): item is Separator {
  return (item as Separator).type === "separator";
}

function isLabel(
  item: Option | OptionDropdown | Separator | Label,
): item is Label {
  return (item as Label).type === "label";
}

export function SubdocsMenu({
  options,
  ...props
}: {
  options: (Option | OptionDropdown | Separator | Label)[];
} & HTMLAttributes<HTMLButtonElement>): React.ReactElement {
  const pathname = usePathname();

  // State for tracking user's explicit navigation preference
  const [storedPreference, setStoredPreference] = useState<string | null>(null);
  const [isInitialized, setIsInitialized] = useState(false);
  const [previousPath, setPreviousPath] = useState<string | null>(null);

  // Load stored preference on mount
  useEffect(() => {
    const preference = getStoredNavPreference();
    setStoredPreference(preference);
    setIsInitialized(true);
  }, []);

  // Handle navigation changes from external sources (browser back/forward) and any route change
  useEffect(() => {
    handleNavigationScroll(previousPath || pathname, pathname);
    scrollSidebarToSelectedItem(pathname);
    setPreviousPath(pathname);
  }, [pathname, previousPath]);

  const selected: Option | undefined = useMemo(() => {
    // Don't calculate selection until we've loaded the stored preference
    if (!isInitialized) return undefined;

    // Get all available options for easier searching
    const allOptions = options.filter(isOption) as Option[];
    const dropDowns = options.filter((item) =>
      isOptionDropdown(item),
    ) as OptionDropdown[];
    let dropdownOptions: Option[] = [];

    if (dropDowns.length > 0) {
      const dropDown = dropDowns[0];
      dropdownOptions = dropDown.options;
    }

    // PRIORITY 1: Check if current pathname matches any option (highest priority)
    const activeDropdownOption = dropdownOptions.find((item) =>
      isActive(item.url || DEFAULT_URL, pathname, true),
    );
    if (activeDropdownOption) {
      return activeDropdownOption;
    }

    const activeMainOption = allOptions.find((item) =>
      isActive(item.url || DEFAULT_URL, pathname, true, item.url === "/"),
    );
    if (activeMainOption) {
      return activeMainOption;
    }

    // PRIORITY 2: If no current pathname match, check stored preference
    if (storedPreference) {
      // Check if stored preference matches any main option
      const storedOption = allOptions.find(
        (option) => option.url === storedPreference,
      );
      if (storedOption) {
        return storedOption;
      }

      // Check if stored preference matches any dropdown option
      const storedDropdownOption = dropdownOptions.find(
        (option) => option.url === storedPreference,
      );
      if (storedDropdownOption) {
        return storedDropdownOption;
      }
    }

    // Default fallback
    return undefined;
  }, [options, pathname, storedPreference, isInitialized]);

  // Handle explicit upper nav clicks to store preference
  const handleExplicitNavClick = useCallback((url: string) => {
    setStoredNavPreference(url);
    setStoredPreference(url);
    //closeOnRedirect.current = false;
  }, []);

  const onClick = useCallback(() => {
    // Navigation click handler
  }, []);

  return (
    <div className="flex flex-col gap-1">
      {options.map((item, index) => {
        if (isSeparator(item)) {
          return (
            <hr
              key={`separator-${index}`}
              className="my-2 border-t border-primary/40"
            />
          );
        } else if (isLabel(item)) {
          return (
            <div
              key={`label-${index}`}
              className="px-2 py-1 text-xs font-semibold text-gray-400 uppercase tracking-wider"
            >
              {item.text}
            </div>
          );
        } else {
          return (
            <SubdocsMenuItem
              key={index}
              item={item}
              selected={selected}
              onClick={onClick}
              onExplicitClick={handleExplicitNavClick}
            />
          );
        }
      })}
      <hr className="mt-2 border-t border-primary/40" />
    </div>
  );
}

function SubdocsMenuItem({
  item,
  selected,
  onClick,
  onExplicitClick,
}: {
  item: Option | OptionDropdown;
  selected?: Option;
  onClick?: () => void;
  onExplicitClick?: (url: string) => void;
}) {
  const pathname = usePathname();

  if (isOption(item)) {
    return (
      <Link
        href={item.url ? item.url : (item.href ?? "")}
        target={item.href ? "_blank" : undefined}
        rel={item.href ? "noopener noreferrer" : undefined}
        onClick={() => {
          if (item.href) return;
          handleNavigationScroll(pathname, item.url || DEFAULT_URL);
          scrollSidebarToSelectedItem(item.url || DEFAULT_URL); // Scroll sidebar to selected item
          onClick?.();
          onExplicitClick?.(item.url || DEFAULT_URL);
        }}
        {...item.props}
        className={cn(
          "px-1 py-0.5 rounded-xl flex flex-row gap-3 items-center cursor-pointer group opacity-60 hover:opacity-100",
          item.props?.className,
          selected === item && `opacity-100 bg-primary/10 text-primary`,
        )}
        suppressHydrationWarning
      >
        <div className={cn("rounded-sm p-1 pr-0 text-primary opacity-100")}>
          {item.icon}
        </div>
        <div>{item.title}</div>
      </Link>
    );
  } else if (isOptionDropdown(item)) {
    return (
      <SubdocsMenuItemDropdown
        item={item}
        selected={selected}
        onClick={onClick}
        onExplicitClick={onExplicitClick}
      />
    );
  }
}

function SubdocsMenuItemDropdown({
  item,
  selected,
  onClick,
  onExplicitClick,
}: {
  item: OptionDropdown;
  selected?: Option;
  onClick?: () => void;
  onExplicitClick?: (url: string) => void;
}) {
  const router = useRouter();
  const selectRef = useRef(null);
  const pathname = usePathname();

  const selectedOption = item.options.find(
    (option) => option.url === selected?.url,
  );

  // Check if we're on a page that should reset the dropdown
  const topLevelPages = ["/", "/reference"];
  const shouldResetDropdown = topLevelPages.some((page) =>
    page === "/" ? pathname === "/" : pathname.startsWith(page),
  );

  const isSelected = selectedOption !== undefined && !shouldResetDropdown;

  return (
    <div className="w-full">
      <Select
        key={shouldResetDropdown ? "reset" : "normal"}
        onValueChange={(url) => {
          handleNavigationScroll(pathname, url);
          scrollSidebarToSelectedItem(url); // Scroll sidebar to selected item
          router.push(url);
          onClick?.();
          onExplicitClick?.(url);
          if (selectRef.current) {
            setTimeout(() => {
              (selectRef.current as any).blur();
            }, 10);
          }
        }}
        value={shouldResetDropdown ? "" : selectedOption?.url || ""}
      >
        <SelectTrigger
          className={cn(
            "pl-1 py-0.5 h-auto flex gap-3 items-center w-full shadow-none rounded-xl cursor-pointer opacity-60 hover:opacity-100",
            !isSelected && "border-2",
            isSelected && "border-0 opacity-100 bg-primary/10 text-primary",
          )}
          style={
            !isSelected ? { borderColor: "oklch(0.65 0.15 285)" } : undefined
          }
          ref={selectRef}
        >
          <SelectValue
            placeholder={
              <div className="flex items-center">
                <div
                  className={cn(
                    "rounded-sm mr-2 p-1 pr-0 text-primary opacity-100",
                    selectedOption?.props?.className,
                  )}
                >
                  {selectedOption?.icon || (
                    <PlugIcon
                      className="w-4 h-4"
                      style={{
                        fontSize: "16px",
                        width: "16px",
                        height: "16px",
                      }}
                    />
                  )}
                </div>
                <div>{item.title}</div>
              </div>
            }
          />
        </SelectTrigger>
        <SelectContent className="p-1 rounded-2xl max-h-[800px] shadow-lg">
          {item.options.map((option, index) => (
            <SelectItem
              key={`${option.url}-${index}`}
              value={option.url ?? DEFAULT_URL}
              className={cn(
                "pl-1 py-0.5 my-0 border-0 h-auto flex gap-3 items-center w-full shadow-none rounded-xl cursor-pointer opacity-60 hover:opacity-100 hover:bg-secondary/10",
                option.props?.className,
              )}
            >
              <div className="flex items-center">
                <div className={cn("rounded-sm p-1 mr-2 text-primary")}>
                  {option.icon}
                </div>
                <span>{option.title}</span>
              </div>
            </SelectItem>
          ))}
        </SelectContent>
      </Select>
    </div>
  );
}
