import { cloneElement, forwardRef } from "react";

import { Box } from "../box";
import { useScrollbarWidth } from "../../utils";
import {
  StyledContent,
  StyledCount,
  StyledList,
  StyledTabs,
  StyledTabName,
  StyledTrigger,
} from "./tabs.styled";

import type { UrlObject } from "url";

interface TabData {
  index: string;
  tabName:
    | string
    | React.ReactElement<{
        href: string | UrlObject;
        children?: React.ReactNode;
        onMouseDown: (e: MouseEvent) => void;
      }>;
  content: React.ReactNode;
  count?: number | undefined;
}

export interface TabsProps extends React.ComponentProps<typeof StyledTabs> {
  ariaLabel: string;
  defaultTab: string;
  tabs: TabData[];
  listProps?: Omit<React.ComponentProps<typeof StyledList>, "aria-label" | "data-show-scrollbars">;
  triggerProps?: Omit<React.ComponentProps<typeof StyledTrigger>, "value">;
  contentProps?: Omit<React.ComponentProps<typeof StyledContent>, "value">;
}

export const Tabs = forwardRef<HTMLDivElement, TabsProps>(
  // eslint-disable-next-line max-lines-per-function
  (
    {
      ariaLabel,
      defaultTab,
      tabs,
      onValueChange,
      value,
      listProps,
      triggerProps,
      contentProps,
      ...rootProps
    },
    ref
  ) => {
    const width = useScrollbarWidth();
    const shouldOverrideScrollbars = width > 0;

    return (
      <StyledTabs
        defaultValue={defaultTab}
        {...(onValueChange && { onValueChange })}
        {...(value && { value })}
        {...rootProps}
        ref={ref}
      >
        <StyledList
          {...listProps}
          aria-label={ariaLabel}
          data-show-scrollbars={String(shouldOverrideScrollbars)}
        >
          {tabs.map((tab) => {
            const count = typeof tab.count === "number" && (
              <StyledCount variant="body5">{tab.count}</StyledCount>
            );
            const tabName =
              typeof tab.tabName !== "string" ? (
                cloneElement(
                  tab.tabName,
                  {
                    onMouseDown: (e: MouseEvent) => {
                      if (process.env.NODE_ENV !== "development") {
                        // prevent default prohibits actual tab change in the radix tab component
                        // new page will be loaded because of URL change, and it will take care of updating the contents

                        // but on development it's slow for next.js to rebuild the page (it does that on each navigation)
                        // so we allow this tab change to happen on development - it causes blink, but faster = better DX
                        e.preventDefault();
                      }
                    },
                  },
                  <>
                    <StyledTabName variant="h5">{tab.tabName.props.children}</StyledTabName>
                    {count}
                  </>
                )
              ) : (
                <>
                  <StyledTabName variant="h5">{tab.tabName}</StyledTabName>
                  {count}
                </>
              );

            return (
              <StyledTrigger
                key={tab.index}
                {...triggerProps}
                value={tab.index}
                asChild={typeof tab.tabName !== "string" ? true : triggerProps?.asChild || false}
              >
                {tabName}
              </StyledTrigger>
            );
          })}
        </StyledList>
        {tabs.map((tab) => {
          return (
            <StyledContent key={tab.index} {...contentProps} value={tab.index}>
              <Box css={{ mt: "$4" }}>{tab.content}</Box>
            </StyledContent>
          );
        })}
      </StyledTabs>
    );
  }
);

Tabs.displayName = "Tabs";
