import Badge, { BadgeAssets, BadgeProps, BadgeAssetsProps } from '../badge';
import Dot, { DotProps } from './Dot';
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 = Omit<BadgeAssetsProps, 'size'> &
  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;
  badge?: AvatarViewBadgeProps;
  interactive?: boolean;
  selected?: boolean;
  style?: Pick<React.CSSProperties, 'border' | 'backgroundColor' | 'color'>;
} & Pick<
  HTMLAttributes<HTMLDivElement>,
  'id' | 'className' | 'children' | 'role' | 'aria-label' | 'aria-labelledby' | 'aria-hidden'
>;

function AvatarView({
  children = undefined,
  size = 48,
  selected,
  badge,
  interactive = false,
  className,
  style,
  imgSrc,
  profileType,
  profileName,
  ...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, selected }} {...badge}>
        <Circle
          size={size}
          fixedSize
          className={clsx('np-avatar-view-content')}
          enableBorder={!interactive || selected}
          style={{
            ...(selected && {
              '--circle-border-color': 'var(--color-interactive-primary)',
              '--circle-border-width': `${MAP_SELECTED_BORDER_WIDTH[size]}px`,
            }),
            ...style,
          }}
        >
          <AvatarViewContent {...{ imgSrc, profileType, profileName }}>
            {children}
          </AvatarViewContent>
        </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']>;

/** Border width for `selected` state determined by avatar size */
const MAP_SELECTED_BORDER_WIDTH = {
  16: 1,
  24: 1,
  32: 1,
  40: 2,
  48: 2,
  56: 2,
  72: 2,
};

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

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

/**
 * Adds build-in badges to AvatarView
 */
function Badges({
  children,
  avatar,
  'aria-label': ariaLabel,
  asset: customBadge,
  ...badgeAssets
}: BadgesProps) {
  const { size = 48, selected } = avatar;
  const anyBadge = Object.values({ customBadge, ...badgeAssets }).filter(Boolean).length > 0;

  if ((!anyBadge && !selected) || size <= 16) {
    return children;
  }

  if (badgeAssets.type === 'notification' || badgeAssets.type === 'online') {
    return (
      <Dot avatarSize={size} variant={badgeAssets.type === 'online' ? 'online' : 'notification'}>
        {children}
      </Dot>
    );
  }

  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>
  );
}

function AvatarViewContent({
  children,
  imgSrc,
  profileName: name,
  profileType: type,
}: PropsWithChildren<Pick<Props, 'imgSrc' | 'profileName' | 'profileType'>>) {
  const [tryLoadImage, setTryLoadImage] = useState(true);
  if (children === undefined) {
    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 />;
  }
  return children;
}

export default AvatarView;
