import {
  Breadcrumb,
  BreadcrumbItem,
  BreadcrumbLink,
  BreadcrumbSeparator,
  BreadcrumbEllipsis,
  BreadcrumbPage,
  BreadcrumbList,
} from './Breadcrumb'

export type CollapsibleBreadcrumbItemProps = {
  label?: string
  href?: string
}

export type CollapsibleBreadcrumbProps = {
  /**
   * Array of breadcrumb items to render.
   * Each item should be an object with the following properties:
   * - label: The text to display.
   * - href: The URL to navigate to.
   */
  items: CollapsibleBreadcrumbItemProps[]
  /**
   * A render function to be used for rendering links, e.g., with a custom Link component.
   * It should accept a label and an href, and return a React element.
   */
  renderLink?: ({
    label,
    href,
    className,
    children,
  }: {
    href: string
    className?: string
  } & (
    | {
        label?: never
        children?: React.ReactNode
      }
    | {
        label?: string
        children?: never
      }
  )) => React.ReactNode
  /**
   * Whether the ellipsis dropdown should be open by default.
   */
  defaultOpen?: boolean
}

type DisplaySlot =
  | { type: 'link'; index: number }
  | { type: 'ellipsis'; collapsedIndices: number[] }
  | { type: 'page'; index: number }

/**
 * Returns an array of display slots for the breadcrumb.
 * - For 4 or fewer items: all items are shown, with the last one marked as the current page.
 * - For more than 4 items: display the first item as a link, an ellipsis with collapsed items,
 *   the second-to-last item as a link, and the last item as the current page.
 *   Rule: First and last two page links are shown, remaining items are collapsed into ellipsis.
 */
const getDisplaySlots = (total: number): DisplaySlot[] => {
  if (total <= 4) {
    return Array.from({ length: total }, (_, index) => {
      if (index === total - 1) {
        return { type: 'page', index }
      }
      return { type: 'link', index }
    })
  }
  // Collapsed items are from index 1 to total-3 (inclusive)
  const collapsedIndices = Array.from({ length: total - 3 }, (_, i) => i + 1)
  return [
    { type: 'link', index: 0 },
    { type: 'ellipsis', collapsedIndices },
    { type: 'link', index: total - 2 },
    { type: 'page', index: total - 1 },
  ]
}

const renderBreadcrumbContent = (
  slot: DisplaySlot,
  items: CollapsibleBreadcrumbItemProps[],
  renderLink?: CollapsibleBreadcrumbProps['renderLink'],
  defaultOpen?: boolean,
) => {
  if (slot.type === 'ellipsis') {
    const collapsedItems = slot.collapsedIndices.map((index) => ({
      href: items[index]?.href,
      label: items[index]?.label,
    }))
    return (
      <BreadcrumbEllipsis
        items={collapsedItems}
        defaultOpen={defaultOpen}
        renderLink={
          renderLink
            ? ({ href, children }) => renderLink({ href, children })
            : undefined
        }
      />
    )
  }

  if (slot.type === 'page') {
    return <BreadcrumbPage>{items[slot.index]?.label}</BreadcrumbPage>
  }

  if (renderLink) {
    return (
      <BreadcrumbLink asChild>
        {renderLink({
          label: items[slot.index]?.label ?? '',
          href: items[slot.index]?.href ?? '',
        })}
      </BreadcrumbLink>
    )
  }

  return (
    <BreadcrumbLink href={items[slot.index]?.href}>
      {items[slot.index]?.label}
    </BreadcrumbLink>
  )
}

export const CollapsibleBreadcrumb = ({
  items,
  renderLink,
  defaultOpen,
}: CollapsibleBreadcrumbProps) => {
  const displaySlots = getDisplaySlots(items.length)

  return (
    <Breadcrumb>
      <BreadcrumbList>
        {displaySlots.map((slot, index) => (
          <BreadcrumbItem key={index}>
            {renderBreadcrumbContent(slot, items, renderLink, defaultOpen)}
            {(displaySlots.length === 1 || index < displaySlots.length - 1) && (
              <BreadcrumbSeparator />
            )}
          </BreadcrumbItem>
        ))}
      </BreadcrumbList>
    </Breadcrumb>
  )
}
