import Badge, { BadgeAssets, BadgeProps, BadgeAssetsProps } from '../badge';
import NotificationDot from './NotificationDot';
import Circle from '../common/circle';
import Image from '../image';
import { HTMLAttributes, PropsWithChildren, useState } from 'react';
import { clsx } from 'clsx';
import { getInitials, ProfileType, ProfileTypeBusiness, ProfileTypePersonal } from '../common';
import {
  Briefcase as BusinessProfileIcon,
  Profile as PersonalProfileIcon,
} from '@transferwise/icons';

export type AvatarViewBadgeProps = BadgeAssetsProps &
  Pick<BadgeProps, 'aria-label'> & {
    /**
     * Custom badge content
     */
    asset?: React.ReactNode;
  };

export type Props = {
  imgSrc?: string | null;
  /**
   * Entity name (person (profile or recipient) or business name), it will be boilded down to 1 or 2 chars (initials)
   */
  profileName?: string | null;
  profileType?: ProfileTypeBusiness | ProfileTypePersonal;
  size?: 16 | 24 | 32 | 40 | 48 | 56 | 72;
  notification?: boolean;
  badge?: AvatarViewBadgeProps;
  interactive?: boolean;
  selected?: boolean;
  style?: Pick<React.CSSProperties, 'border' | 'backgroundColor' | 'color'>;
} & Pick<
  HTMLAttributes<HTMLDivElement>,
  'className' | 'children' | 'role' | 'aria-label' | 'aria-labelledby' | 'aria-hidden'
>;

function AvatarView({
  children = undefined,
  size = 48,
  selected,
  notification,
  badge,
  interactive = false,
  className,
  style,
  imgSrc,
  profileType: type,
  profileName: name,
  ...restProps
}: Props) {
  return (
    <Circle
      size={size}
      fixedSize
      className={clsx(
        'np-avatar-view',
        interactive ? 'np-avatar-view-interactive' : 'np-avatar-view-non-interactive',
        { 'np-avatar-view-selected': selected },
        className,
      )}
      {...restProps}
    >
      <Badges avatar={{ size, notification, selected }} {...badge}>
        <Circle
          size={size}
          fixedSize
          className={clsx('np-avatar-view-content')}
          enableBorder={!interactive || selected}
          style={{
            ...(selected && { '--circle-border-color': 'var(--color-interactive-primary)' }),
            ...style,
          }}
        >
          {children === undefined ? (
            <AvatarViewContent {...{ imgSrc, profileType: type, profileName: name }} />
          ) : (
            children
          )}
        </Circle>
      </Badges>
    </Circle>
  );
}

/** Size of badge depends on size of avatar */
const MAP_BADGE_ASSET_SIZE = {
  16: 16,
  24: 16,
  32: 16,
  40: 16,
  48: 16,
  56: 24,
  72: 24,
} satisfies Record<number, BadgeAssetsProps['size']>;

/** Certain sizes of AvatarView has a custom offset of Badge */
const MAP_BADGE_POSITION = {
  24: -6,
  32: -4,
};

type BadgesProps = AvatarViewBadgeProps &
  PropsWithChildren<{
    avatar: Pick<Props, 'selected' | 'size' | 'notification'>;
  }>;

/**
 * Adds build-in badges to AvatarView
 */
function Badges({
  children,
  avatar,
  'aria-label': ariaLabel,
  asset: customBadge,
  ...badgeAssets
}: BadgesProps) {
  const { size = 48, selected, notification } = avatar;
  const anyBadge = Object.values({ customBadge, ...badgeAssets }).filter(Boolean).length > 0;
  if ((anyBadge || selected) && size > 16) {
    const badgeSize: BadgeAssetsProps['size'] = MAP_BADGE_ASSET_SIZE[size];
    return (
      <Badge
        aria-label={ariaLabel}
        size={badgeSize}
        badge={
          customBadge ? (
            <Circle fixedSize size={badgeSize}>
              {customBadge}
            </Circle>
          ) : (
            <BadgeAssets {...(selected ? { status: 'positive' } : badgeAssets)} size={badgeSize} />
          )
        }
        style={{
          // @ts-expect-error CSS custom props allowed
          '--badge-content-position': `${MAP_BADGE_POSITION[size] ?? 0}px`,
        }}
      >
        {children}
      </Badge>
    );
  }
  if (notification) {
    return <NotificationDot avatarSize={size}>{children}</NotificationDot>;
  }
  return children;
}

function AvatarViewContent({
  imgSrc,
  profileName: name,
  profileType: type,
}: Pick<Props, 'imgSrc' | 'name' | 'type'>) {
  const [tryLoadImage, setTryLoadImage] = useState(true);
  if (imgSrc && tryLoadImage) {
    return <Image src={imgSrc} alt="" onError={() => setTryLoadImage(false)} />;
  }
  if (type) {
    return type === ProfileType.BUSINESS ? <BusinessProfileIcon /> : <PersonalProfileIcon />;
  }
  if (name) {
    return getInitials(name);
  }
  return <PersonalProfileIcon />;
}

export default AvatarView;
