"use client"
import React, {
  ComponentProps,
  ComponentRef,
  forwardRef,
  useContext,
  useState,
} from "react"
import { tv } from "tailwind-variants"
import { classNames } from "../../utils"
import { isInteractiveElement } from "../../utils/element"
import { Collapsible, CollapsibleProps } from "../Collapsible"
import { Flex } from "../Flex"
import { FlexColumn } from "../FlexColumn"
import { Item, ItemProps } from "../Item"
import { Separator } from "../Separator"
import { SidebarContext } from "./SidebarContext"
import { SidebarOpen } from "./SidebarOpen"

type SidebarItemProps = {
  active?: boolean
  renderItem?: React.ComponentType<ItemProps>
  size?: "sm" | "md"
} & ItemProps

const sidebarItemVariants = tv({
  base: "flex w-full flex-nowrap items-center gap-2 rounded-md bg-transparent p-2",
  variants: {
    interactive: {
      true: "text-text-secondary transition-colors duration-200 ease-out-quint hover:bg-bg-additional-2 hover:text-text-primary",
    },
    active: {
      true: "bg-bg-additional-2 text-text-primary [&[data-state=open]]:text-text-primary",
    },
    size: {
      sm: "h-7 px-2 py-1",
      md: "h-9",
    },
  },
})

const SidebarItemBase = forwardRef<ComponentRef<typeof Item>, SidebarItemProps>(
  function SidebarItem(
    {
      active,
      children,
      renderItem,
      className,
      interactive,
      onClick,
      size = "md",
      ...rest
    },
    ref,
  ) {
    const { setDisableExpand } = useContext(SidebarContext)
    const Comp = renderItem ?? Item

    const isInteractive =
      interactive ?? isInteractiveElement({ ...rest, onClick })

    return (
      <Comp
        className={classNames(
          sidebarItemVariants({ active, interactive: isInteractive, size }),
          className,
        )}
        interactive={isInteractive}
        ref={ref}
        variant="unstyled"
        onClick={e => {
          onClick?.(e)
          setDisableExpand(true)
        }}
        {...rest}
      >
        {children}
      </Comp>
    )
  },
)

type SidebarCollapsibleItemProps = CollapsibleProps & {
  active?: boolean
}

export const SidebarCollapsibleItem = forwardRef<
  ComponentRef<typeof Collapsible>,
  SidebarCollapsibleItemProps
>(function SidebarCollapsibleItem(
  {
    children,
    className,
    active,
    content,
    toggleClosedDirection = "right",
    overrides,
    onOpenChange,
    ...rest
  },
  ref,
) {
  const [open, setOpen] = useState(rest.open)
  const { disableExpand, setDisableExpand } = useContext(SidebarContext)
  return (
    <Collapsible
      {...rest}
      className={classNames(
        "[&[data-state=open]]:text-text-secondary [&[data-state=open]]:group-hover:text-text-primary",
        sidebarItemVariants({ active, interactive: true, size: "md" }),
        className,
      )}
      content={
        <SidebarOpen>
          <Flex className="py-2">
            <Separator
              className="ml-[17.5px] mr-[9.5px] h-auto"
              orientation="vertical"
            />
            <FlexColumn className="grow gap-2">{content}</FlexColumn>
          </Flex>
        </SidebarOpen>
      }
      overrides={{
        ...overrides,
        Icon: {
          className: classNames("order-3"),
          ...overrides?.Icon,
        },
      }}
      ref={ref}
      toggleClosedDirection={toggleClosedDirection}
      onClick={e => {
        if (disableExpand) {
          setDisableExpand(false)
          if (open) {
            e.preventDefault()
          }
        }
      }}
      onOpenChange={newOpen => {
        setOpen(newOpen)
        onOpenChange?.(newOpen)
      }}
    >
      {/* div prevents Collapsible's selector rotating Item avatar */}
      <div className="contents">{children}</div>
    </Collapsible>
  )
})

export const SidebarAvatar = ({
  className,
  ...rest
}: ComponentProps<typeof Item.Avatar>) => {
  return (
    <Item.Avatar
      className={classNames("text-current", className)}
      size={20}
      {...rest}
    />
  )
}

export const SidebarItemTitle = ({
  children,
  className,
  size = "md",
}: {
  children: React.ReactNode
  className?: string
  size?: "sm" | "md"
}) => {
  return (
    <Item.Content>
      <Item.Title
        className={classNames(
          "whitespace-nowrap font-inherit opacity-0 transition-opacity group-hover:opacity-100",
          className,
        )}
        size={size}
      >
        {children}
      </Item.Title>
    </Item.Content>
  )
}

export const SidebarItem = Object.assign(SidebarItemBase, {
  Avatar: SidebarAvatar,
  Title: SidebarItemTitle,
})
