import { useEffect, useState } from 'react'

import { omitThemingProps, styled, useStyleConfig, vui } from '../core'
import Icon, { IconProp, IconProps } from '../icon'
import Image from '../image'
import { cs, filterUndefined } from '../utils'
import { loadImageUrl } from '../utils/images'
import { AvatarProps } from './avatar.types'
import { defaultGetInitials } from './helpers'

export const AvatarBase = styled.spanBox`
  align-items: center;
  display: inline-flex;
  flex-shrink: 0;
  font-weight: medium;
  justify-content: center;
  line-height: normal;
  outline: none;
  overflow: hidden;
  transition-duration: fast;

  &:focus {
    border-color: transparent;
  }

  &[aria-disabled='true'] {
    opacity: 0.5;
    cursor: not-allowed;
    user-select: none;
  }
`

/** Displays user data, such as name initials or profile image. */
export const Avatar = vui<'span', AvatarProps>((props, ref) => {
  const {
    children,
    className,
    disabled,
    getInitials = defaultGetInitials,
    icon,
    isInteractive = props.onClick !== undefined,
    isSquare,
    name = '',
    src,
    ...rest
  } = omitThemingProps(props)
  const { activeBg, h, hoverBg, iconSize, ...styles } = useStyleConfig('Avatar', props)

  const borderRadius = isSquare ? (props.size === 'sm' ? '3px' : '6px') : '50%'
  const initials = getInitials(name)

  const interactiveProps =
    !disabled && isInteractive
      ? ({
          cursor: 'pointer',
          hoverBg,
          hoverOpacity: src ? 0.85 : 1,
          activeOpacity: src ? 0.7 : 1,
          activeBg,
          focusRing: 3,
          tabIndex: 0,
          userSelect: 'none',
        } as const)
      : {}

  const aliasedProps = filterUndefined({
    borderRadius: borderRadius,
    'aria-disabled': disabled,
  })

  return (
    <AvatarBase
      borderRadius={borderRadius}
      className={cs('vui-avatar', className)}
      h={h}
      ref={ref}
      w={h}
      {...styles}
      {...interactiveProps}
      {...aliasedProps}
      {...rest}
    >
      {children ? (
        children
      ) : src ? (
        <LazyImageOrDefault borderRadius={borderRadius} icon={icon} iconSize={iconSize} initials={initials} src={src} />
      ) : icon ? (
        <Icon name={icon} size={iconSize} />
      ) : initials ? (
        initials
      ) : (
        <Icon name="falUser" size={iconSize} />
      )}
    </AvatarBase>
  )
})

function LazyImageOrDefault({
  src,
  borderRadius,
  icon,
  iconSize,
  initials,
}: {
  src: string
  borderRadius: string
  icon: IconProp | undefined
  iconSize: IconProps['size']
  initials: string
}) {
  const [imgLoaded, setImgLoaded] = useState(false)
  useEffect(() => {
    let cancelled = false
    loadImageUrl(src).then(res => {
      if (!cancelled) setImgLoaded(res)
    })
    return () => {
      cancelled = true
    }
  }, [src])

  return imgLoaded ? (
    <Image borderRadius={borderRadius} src={src} />
  ) : icon ? (
    <Icon name={icon} size={iconSize} />
  ) : initials ? (
    <>{initials}</>
  ) : (
    <Icon name="falUser" size={iconSize} />
  )
}

Avatar.displayName = 'Avatar'
export default Avatar
