/* eslint-disable react/no-unused-prop-types */
import { useState, useMemo } from 'react';
import PropTypes from 'prop-types';
import { ErrorBoundary } from 'react-error-boundary';
import { Shape } from '@arcblock/did-motif';
import { Box } from '@mui/material';
import isUndefined from 'lodash/isUndefined';

import Img from '../Img';
import { mergeProps, isEthereumDid } from '../Util';
import DIDMotif from './did-motif';
import blockies from './etherscan-blockies';
import { DID_PREFIX } from '../Util/constant';

/**
 * Avatar component
 * @typedef {{
 *  src?: string;
 *  did?: string;
 *  size?: number;
 *  variant?: 'circle' | 'rounded' | 'default';
 *  animation?: false | true;
 *  shape?: '' | 'rectangle' | 'square' | 'hexagon' | 'circle';
 *  blockiesPadding?: true | false;
 *  responsive?: false | true;
 *  useProxyFallback?: boolean;
 * } & Omit<import('../Img').ImgProps, 'size' | 'src'>} AvatarProps
 */

/**
 * @see 参考: https://github.com/blocklet/block-explorer/issues/478#issuecomment-1038954976
 * @param {AvatarProps} props
 * @returns {JSX.Element}
 */
function Avatar({ ...rawProps }) {
  const props = Object.assign({}, rawProps);
  if (isUndefined(props.did)) {
    props.did = '';
  }
  if (isUndefined(props.size)) {
    props.size = 36;
  }
  if (isUndefined(props.variant)) {
    props.variant = 'default';
  }
  if (isUndefined(props.animation)) {
    props.animation = false;
  }
  if (isUndefined(props.shape)) {
    props.shape = '';
  }
  if (isUndefined(props.blockiesPadding)) {
    props.blockiesPadding = true;
  }
  if (isUndefined(props.responsive)) {
    props.responsive = false;
  }
  const [imgError, setImgError] = useState(false);
  /** @type {AvatarProps} */
  const newProps = mergeProps(props, Avatar, []);
  const { did = '', size, src, variant, animation, shape, blockiesPadding, responsive, ...rest } = newProps;

  // ethereum blockies
  const blockyIcon = useMemo(() => {
    if (isEthereumDid(did)) {
      return blockies
        .createIcon({
          seed: did.replace(DID_PREFIX, '').toLowerCase(),
          size: 8,
          scale: 16,
        })
        .toDataURL();
    }
    return null;
  }, [did]);

  // 如果显式传入 src 则直接使用 src
  if (src && !imgError) {
    return (
      <Img
        width={size}
        src={src}
        alt={did}
        onError={() => setImgError(true)}
        {...rest}
        // HACK: 这个 className 是传递给子元素的，所以下面的 sx 需要通过子元素选择器来写样式
        className={`avatar-img--${variant} ${rest?.className || ''}`}
        useProxyFallback
        sx={{
          '& .avatar-img--rounded': {
            borderRadius: '4px',
            overflow: 'hidden',
          },
          '& .avatar-img--circle': {
            borderRadius: '100%',
            overflow: 'hidden',
          },
          ...rest.sx,
        }}
      />
    );
  }
  // 对于 eth address, 渲染成 blocky icon, 形状与 account role type 的 did motif 相似都为矩形, 高宽比为 0.7
  if (blockyIcon) {
    if (blockiesPadding) {
      // blocky icon 要与灰色卡片矩形留有空间
      const padding = size > 24 ? 4 : 2;
      return (
        <Box
          {...rest}
          sx={{
            display: 'flex',
            alignItems: 'center',
            width: size,
            height: size,
            '.blocky-icon-inner': {
              boxSizing: 'border-box',
              display: 'flex',
              justifyContent: 'center',
              alignItems: 'center',
              width: size,
              height: size * 0.7,
              borderRadius: `${Math.min(10, Math.floor(0.1 * size + 2))}px`,
              background: '#ddd',
            },
            ...rest.sx,
          }}>
          <div className="blocky-icon-inner">
            <Img width={size * 0.7 - padding * 2} src={blockyIcon} alt={did} />
          </div>
        </Box>
      );
    }

    return <Img {...rest} width={size} src={blockyIcon} alt={did} style={{ marginRight: 4 }} />;
  }

  if (did) {
    // 渲染 did motif
    return (
      <DIDMotif
        did={did.replace(DID_PREFIX, '')}
        size={size}
        animation={animation}
        shape={Shape[(shape || '').toUpperCase()]}
        responsive={responsive}
        {...rest}
      />
    );
  }
  throw new Error(`Invalid DID: ${did}`);
}

Avatar.propTypes = {
  did: PropTypes.string,
  size: PropTypes.number,
  variant: PropTypes.oneOf(['circle', 'rounded', 'default']),
  // animation 仅对 did motif 有效
  animation: PropTypes.bool,
  // shape 仅对 did motif 有效, 明确指定 motif shape, 而非由 did role type 自动推断 shape
  shape: PropTypes.oneOf(['', 'rectangle', 'square', 'hexagon', 'circle']),
  blockiesPadding: PropTypes.bool,
  responsive: PropTypes.bool,
  useProxyFallback: PropTypes.bool,
};

/**
 * @param {AvatarProps} props
 * @returns {JSX.Element}
 */
export default function AvatarWithErrorBoundary(props) {
  const size = props.size || 36;
  const borderRadius = { rounded: '4px', circle: '100%' }[props.variant] || 0;
  return (
    <ErrorBoundary
      // eslint-disable-next-line react/no-unstable-nested-components
      fallbackRender={() => (
        <Box
          sx={{
            width: size,
            height: size,
            bgcolor: 'grey.300',
            borderRadius,
          }}
        />
      )}>
      <Avatar {...props} />
    </ErrorBoundary>
  );
}

AvatarWithErrorBoundary.propTypes = Avatar.propTypes;

// Export Avatar for access to its props
export { Avatar as AvatarProps };
