"use client"
import React, { ComponentPropsWithoutRef, forwardRef } from "react"
import { tv } from "tailwind-variants"
import { type VariantProps } from "tailwind-variants"
import { classNames } from "../../utils"
import { Item, ItemProps } from "../Item"
import { Text, TextBodyProps } from "../Text"
import { ListGroup } from "./ListGroup"
import { ListHeader } from "./ListHeader"

export type ListProps = ComponentPropsWithoutRef<"ul"> &
  VariantProps<typeof listVariants> & {
    height?: number
  }

const listVariants = tv({
  variants: {
    showBorder: {
      true: classNames(
        "border border-border-2",
        "*:not-last:!border-b *:not-last:border-b-border-2",
      ),
    },
    variant: {
      default: "rounded-xl bg-bg-app",
      condensed: classNames(
        "rounded-xl bg-bg-app",
        "[&_[data-id=Item]]:px-4",
        "[&_[data-id=Item]]:py-2",
        "[&_[data-id=ItemTitle]]:font-normal",
        "[&_[data-id=ItemContent]]:mr-0",
      ),
      // This variant is used within a container that already has border styles
      framed: classNames(
        "rounded-none border-0 bg-inherit *:rounded-none",
        "[&_[data-id=Item]]:rounded-none",
      ),
    },
  },
})

const ListBase = forwardRef<HTMLUListElement, ListProps>(function List(
  {
    className,
    children,
    height,
    showBorder = true,
    variant = "default",
    ...rest
  },
  ref,
) {
  return (
    <ul
      className={classNames(
        "*:first:rounded-t-xl *:last:rounded-b-xl",
        "[&_[data-id=Item]]:border-0",
        "[&_[data-id=Item]]:overflow-hidden",
        listVariants({ showBorder, variant }),
        className,
      )}
      ref={ref}
      style={{
        height: height ? `${height}px` : undefined,
        // If a height is set, content should scroll within the container
        overflow: height ? "auto" : undefined,
      }}
      {...rest}
    >
      {children}
    </ul>
  )
})

export const ListItem = Object.assign(
  forwardRef<HTMLLIElement, ItemProps>(function ListItem(
    { asChild, children, ...props },
    ref,
  ) {
    return (
      <Item asChild={asChild} {...props} ref={ref}>
        {children}
      </Item>
    )
  }),
  {
    Avatar: Item.Avatar,
    Content: Item.Content,
    Title: Item.Title,
    Description: Item.Description,
    Side: Item.Side,
    Action: Item.Action,
  },
)

export const ListItemValue = ({
  weight = "semibold",
  ...rest
}: TextBodyProps) => {
  return <Text weight={weight} {...rest} />
}

/**
 * Renders a list of `Item`s. Can also render groupings of items along with associated headers.
 */
export const List = Object.assign(ListBase, {
  Item: Object.assign(ListItem, { Value: ListItemValue }),
  Header: ListHeader,
  Group: ListGroup,
})
