/* eslint-disable max-lines-per-function */
import { forwardRef, memo } from "react";

import { omit } from "../../utils";
import { IconButton } from "../icon-button";
import { Icons } from "../icons";
import {
  CrumbListItem,
  CrumbsList,
  CrumbText,
  OverflowContent,
  OverflowCrumbsTrigger,
  RadixNavigationMenuLink,
  Root,
  StyledCrumbButton,
  SubCrumbLink,
  Crumb as StyledCrumb,
  SubCrumbList,
  SubCrumbListItem,
} from "./breadcrumbs.styled";
import { Crumb } from "./sub-components/crumb";
import { SubCrumb } from "./sub-components/sub-crumb";
import { useBreadcrumbs } from "./use-breadcrumbs";

import type { UrlObject } from "url";
import type { Link } from "../link";

type BaseCrumb = {
  Icon?: React.ReactElement;
};

type Crumb = {
  label: string;
  href: string;
  linkProps?: Omit<React.ComponentProps<typeof Link>, "href">;
} & BaseCrumb;

type LinkCrumb = {
  linkElement: React.ReactElement<{
    href: string | UrlObject;
    children: string;
    style?: React.CSSProperties;
    ref?: React.ForwardedRef<HTMLAnchorElement>;
  }>;
} & BaseCrumb;

type ButtonCrumb = {
  label: string;
  onClick: React.ButtonHTMLAttributes<HTMLButtonElement>["onClick"];
  buttonProps?: Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, "onClick">;
} & BaseCrumb;

type TextCrumb = {
  label: string;
} & BaseCrumb;

interface Props extends Omit<React.ComponentProps<typeof Root>, "asChild"> {
  /**
   * Array of link elements with string children and optional icon
   */
  crumbs: Array<Crumb | LinkCrumb | ButtonCrumb | TextCrumb>;
  /**
   * Optional custom divider
   */
  divider?: React.ReactNode;
  /**
   * Sets Icon position to end of container. (only affects sub crumbs with icons)
   */
  iconPosition?: "start" | "end";
  /**
   * [Radix Documentation](https://www.radix-ui.com/primitives/docs/components/navigation-menu#list)
   */
  crumbsListProps?: Omit<React.ComponentProps<typeof CrumbsList>, "data-crumb-list">;
  /**
   * [Radix Documentation](https://www.radix-ui.com/primitives/docs/components/navigation-menu#content)
   */
  subCrumbListContainerProps?: React.ComponentProps<typeof OverflowContent>;
  /**
   * [Radix Documentation](https://www.radix-ui.com/primitives/docs/components/navigation-menu#item)
   */
  crumbItemProps?: React.ComponentProps<typeof CrumbListItem>;
  /**
   * [Radix Documentation](https://www.radix-ui.com/primitives/docs/components/navigation-menu#trigger)
   * Only applicable if there is overflow
   */
  subCrumbTriggerProps?: React.ComponentProps<typeof OverflowCrumbsTrigger>;
}

const BreadcrumbsComponent = forwardRef<HTMLElement, Props>((props, ref) => {
  const {
    crumbs,
    divider: customDivider,
    iconPosition,
    crumbsListProps,
    subCrumbListContainerProps,
    crumbItemProps,
    subCrumbTriggerProps,
    ...rest
  } = props;

  const { rootRef, overflowAtIndex, divider } = useBreadcrumbs({
    crumbs,
    customDivider,
    ref,
  });
  return (
    <Root ref={rootRef} {...rest}>
      <CrumbsList data-crumb-list {...omit(crumbsListProps, ["data-crumb-list"])}>
        {typeof overflowAtIndex === "number" && crumbs.length >= 3 ? (
          <>
            <Crumb
              crumb={crumbs[0]!}
              isLast={false}
              isFirst={true}
              divider={divider}
              crumbItemProps={crumbItemProps}
            />

            <CrumbListItem {...crumbItemProps}>
              <OverflowCrumbsTrigger asChild {...omit(subCrumbTriggerProps, ["asChild"])}>
                <IconButton Icon={<Icons.More />} variant="secondary" />
              </OverflowCrumbsTrigger>
              <OverflowContent {...subCrumbListContainerProps}>
                <SubCrumbList>
                  {crumbs.slice(1, overflowAtIndex + 1).map((crumb, i) => (
                    <SubCrumb key={i} crumb={crumb} iconPosition={iconPosition} />
                  ))}
                </SubCrumbList>
              </OverflowContent>
            </CrumbListItem>
            <li aria-hidden="true">{divider}</li>
            {crumbs.slice(overflowAtIndex + 1).map((crumb, i) => {
              const isLast = i === crumbs.slice(overflowAtIndex + 1).length - 1;
              return (
                <Crumb
                  key={i}
                  crumb={crumb}
                  aria-current="page"
                  divider={divider}
                  isLast={isLast}
                  crumbItemProps={crumbItemProps}
                />
              );
            })}
          </>
        ) : (
          crumbs.map((crumb, i) => {
            const isLastCrumb = i === crumbs.length - 1;
            const isFirst = i === 0;

            return (
              <Crumb
                key={i}
                crumb={crumb}
                isFirst={isFirst}
                isLast={isLastCrumb}
                iconPosition={iconPosition}
                divider={divider}
                crumbItemProps={crumbItemProps}
              />
            );
          })
        )}
      </CrumbsList>
      <CrumbsList
        css={{
          ...crumbItemProps?.css,
          position: "fixed",
          visibility: "hidden",
        }}
        data-crumb-list-clone
        {...omit(crumbsListProps, ["css", "data-crumb-list"])}
      >
        {crumbs.map((crumb, i) => {
          const isLastCrumb = i === crumbs.length - 1;

          return (
            <Crumb
              key={i}
              crumb={crumb}
              isLast={isLastCrumb}
              iconPosition={iconPosition}
              divider={divider}
              crumbItemProps={crumbItemProps}
            />
          );
        })}
      </CrumbsList>
    </Root>
  );
});

BreadcrumbsComponent.displayName = "Breadcrumbs";

/**
 * Based on [Radix Primitives Navigation Menu](https://www.radix-ui.com/primitives/docs/components/navigation-menu)
 *
 *
 * The Breadcrumbs component is a navigational tool that visualises the user's path through a website or app. It renders a `<nav>` element at the root level, allowing users to easily backtrack or understand their current location within the site's hierarchy.
 */
export const Breadcrumbs = memo(BreadcrumbsComponent);

export const BreadcrumbsRootSelector = Root.toString();
export const BreadcrumbsCrumbsListSelector = CrumbsList.toString();
export const BreadcrumbsOverflowCrumbsTriggerSelector = OverflowCrumbsTrigger.toString();
export const BreadcrumbsOverflowContentSelector = OverflowContent.toString();
export const BreadcrumbsSubCrumbLinkSelector = SubCrumbLink.toString();
export const BreadcrumbsCrumbSelector = StyledCrumb.toString();
export const BreadcrumbsCrumbButtonSelector = StyledCrumbButton.toString();
export const BreadcrumbsCrumbTextSelector = CrumbText.toString();
export const BreadcrumbsCrumbListItemSelector = CrumbListItem.toString();
export const BreadcrumbsNavigationMEnuLinkSelector = RadixNavigationMenuLink.toString();
export const BreadcrumbsSubCrumbListSelector = SubCrumbList.toString();
export const BreadcrumbsSubCrumbListItemSelector = SubCrumbListItem.toString();
