import { useMemo } from 'react'

import type { VuiComponent } from '../core'
import { styled, useStyleConfig, vui } from '../core'
import { cs, filterUndefined, isReactText, isString } from '../utils'
import { TagProvider } from './context'
import type { TagProps } from './tag.types'
import TagButton from './tagButton'
import TagIcon from './tagIcon'
import TagText from './tagText'

export const TagBase = styled.spanBox`
  align-items: center;
  border-radius: xl;
  display: inline-flex;
  font-weight: medium;
  justify-content: center;
  line-height: normal;
  max-width: 100%;
  position: relative;
  transition-duration: fast;
  width: fit-content;

  &:focus {
    border-color: transparent;
    outline: none;
  }

  &[aria-disabled='true'] {
    opacity: 0.5;
    cursor: not-allowed;
    user-select: none;
  }
`
/**
 * Displays text, icons or custom content. Can be made interactive or a link.
 * Exposes some props to the children via context.
 */
export const Tag = vui<'span', TagProps>((props, ref) => {
  const {
    casing,
    children,
    className,
    disabled,
    icon,
    iconLeft,
    iconRight,
    isFullWidth,
    isInteractive = props.onClick !== undefined && props.onDelete === undefined,
    isRound,
    isTruncated = true,
    itemLeft,
    itemRight,
    onClick,
    onDelete,
    size = 'md',
    text,
    variant = 'subtleBlue',
    weight,
    ...rest
  } = props
  const styles = useStyleConfig('Tag', props)
  const { activeBg, h, hoverBg, spaceX: spaceXBase = 0, ...tagStyles } = styles.container

  const context = useMemo(() => filterUndefined({ disabled, size, variant }), [disabled, size, variant])

  const spaceX = spaceXBase / 8
  let spaceXText = (spaceXBase + 4) / 8
  if (size === 'xs') {
    spaceXText = spaceXBase / 8
  }

  const pl = icon || itemLeft || iconLeft ? spaceX : spaceXText
  const pr = icon || itemRight || iconRight ? spaceX : spaceXText

  const interactiveProps =
    !disabled && isInteractive
      ? {
          cursor: 'pointer',
          hoverBg,
          activeBg,
          tabIndex: 0,
          userSelect: 'none',
        }
      : {}

  const aliasedProps = filterUndefined({
    borderRadius: isRound ? h / 2 : undefined,
    'aria-disabled': disabled,
    fontWeight: weight,
    textTransform: casing,
    w: isFullWidth ? '100%' : undefined,
  })

  return (
    <TagProvider value={context}>
      <TagBase
        className={cs('vui-tag', className)}
        focusRing={2}
        h={h}
        isTruncated={isTruncated}
        onClick={!disabled ? onClick : undefined}
        pl={pl}
        pr={pr}
        ref={ref}
        {...tagStyles}
        {...interactiveProps}
        {...aliasedProps}
        {...rest}
      >
        {isString(icon) ? <TagIcon name={icon} /> : icon}

        {!icon && (
          <>
            {itemLeft}

            {isString(iconLeft) ? <TagIcon mr={spaceX} name={iconLeft} /> : iconLeft}

            {children ?? (isReactText(text) ? <TagText {...{ isTruncated, text }} /> : text)}

            {isString(iconRight) ? <TagIcon ml={spaceX} name={iconRight} /> : iconRight}

            {onDelete ? (
              <TagButton
                aria-label="delete"
                disabled={disabled}
                isRound={isRound}
                ml={spaceX}
                onClick={e => onDelete?.(e)}
              />
            ) : (
              itemRight
            )}
          </>
        )}
      </TagBase>
    </TagProvider>
  )
}) as VuiComponent<'span', TagProps> & {
  Button: typeof TagButton
  Icon: typeof TagIcon
  Text: typeof TagText
}

Tag.Button = TagButton
Tag.Icon = TagIcon
Tag.Text = TagText

Tag.displayName = 'Tag'

export default Tag
