import { useEffect, useMemo, useState } from 'react';
import PropTypes from 'prop-types';
import { useInView } from 'react-intersection-observer';
import WarningRoundedIcon from '@iconify-icons/material-symbols/warning-rounded';
import ImageRoundedIcon from '@iconify-icons/material-symbols/image-rounded';
import { Icon } from '@iconify/react';
import { Box } from '@mui/material';
import noop from 'lodash/noop';
import { mergeSx } from '../Util/style';
import { BLOCKLET_SERVICE_PATH_PREFIX } from '../Util/constant';

const getProxyImageUrl = (url) => {
  if (!url) return '';

  try {
    // 检查是否是一个有效的URL
    const urlObj = new URL(url);

    // 检查协议是否是https
    if (urlObj.protocol !== 'https:') {
      console.warn('Image URL must use HTTPS protocol:', url);
      return '';
    }

    // 返回代理URL
    return `${BLOCKLET_SERVICE_PATH_PREFIX}/proxy?url=${encodeURIComponent(url)}`;
  } catch (error) {
    // URL construction failed, indicating invalid URL format
    console.warn('Invalid image URL format:', url, error);
    return '';
  }
};

/**
 * @typedef {Object} ImgExProps
 * @property {string} src - required
 * @property {string} [alt]
 * @property {string} [size='cover']
 * @property {string} [position='top center']
 * @property {object} [style]
 * @property {number} [ratio=1]
 * @property {string} [repeat='no-repeat']
 * @property {number} [width]
 * @property {number} [height]
 * @property {boolean} [lazy=true]
 * @property {string} [placeholder]
 * @property {string} [fallback]
 * @property {boolean} [useProxyFallback=false] - 是否使用代理 fallback, 用于解决 CSP 的问题
 * @property {string} [className='']
 * @property {function} [onError=() => {}]
 * @property {function} [onSuccess=() => {}]
 */

/**
 * @typedef {ImgExProps & import('@mui/material').BoxProps} ImgProps
 */

const PREFIX = 'Img';

const classes = {
  root: `${PREFIX}-root`,
};

/**
 *
 * @param {ImgProps} props
 * @returns {React.ReactComponentElement}
 */
function Img({
  lazy = true,
  width = null,
  height = null,
  repeat = 'no-repeat',
  ratio = 1,
  alt = null,
  size = 'cover',
  position = 'top center',
  src,
  useProxyFallback = false, // 是否使用代理 fallback, 用于解决 CSP 的问题
  placeholder = null,
  fallback = null,
  style = null,
  className = '',
  onError = noop,
  onSuccess = noop,
  ...rest
}) {
  // eslint-disable-next-line react-hooks/rules-of-hooks
  const [ref, inView] = lazy ? useInView({ threshold: 0, triggerOnce: true }) : [null, true];

  const [imgState, setImgState] = useState('init');
  const [fallbackError, setFallbackError] = useState(false);

  const fallbackSrc = useMemo(() => {
    if (fallback) {
      return fallback;
    }
    if (useProxyFallback && src) {
      return getProxyImageUrl(src);
    }
    return fallback;
  }, [src, useProxyFallback, fallback]);

  const actualSrc = useMemo(() => {
    switch (imgState) {
      case 'init':
      case 'loading':
        return placeholder;
      case 'error':
        return fallbackError ? null : fallbackSrc;
      case 'loaded':
        return src;
      default:
        return null;
    }
  }, [placeholder, fallbackSrc, src, imgState, fallbackError]);

  const actualRatio = width && height ? (100 * height) / width : ratio * 100;

  const mergedStyle = useMemo(
    () => ({
      backgroundImage: actualSrc ? `url(${actualSrc})` : '',
      backgroundPosition: position,
      backgroundSize: size,
      backgroundRepeat: repeat,
      paddingTop: `${actualRatio}%`,
    }),
    // eslint-disable-next-line react-hooks/exhaustive-deps
    [actualSrc, position, size, imgState]
  );

  /**
   * @type {CSSStyleDeclaration}
   */
  const outerStyle = {
    ...style,
    display: 'inline-block',
    width: width ? `${width}px` : '100%',
  };

  function loadImg() {
    const img = new Image();
    img.src = src;
    setImgState('loading');
    setFallbackError(false);
    img.onload = () => {
      setImgState('loaded');
      onSuccess();
    };
    img.onerror = () => {
      setImgState('error');
    };
  }

  useEffect(() => {
    if (inView) loadImg();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [inView]);

  // 处理 fallback 加载
  useEffect(() => {
    if (imgState === 'error' && fallbackSrc && !fallbackError) {
      const fallbackImg = new Image();
      fallbackImg.src = fallbackSrc;
      fallbackImg.onload = () => {
        // fallback 加载成功，保持在 error 状态但显示 fallback
      };
      fallbackImg.onerror = (err) => {
        // fallback 也加载失败
        setFallbackError(true);
        if (imgState === 'error') {
          onError(err);
        }
      };
    }
  }, [imgState, fallbackSrc, fallbackError, onError]);

  return (
    // paddingTop 要求元素本身的宽度为 100%，所以只能加一个外层元素去限制宽度
    <Box
      data-id="2"
      ref={ref}
      style={outerStyle}
      className="arcblock_ux_img-wrapper"
      {...rest}
      sx={mergeSx(
        {
          [`& .${classes.root}`]: {
            position: 'relative',
            overflow: 'hidden',
            '& .image--state, & .image--img': {
              minWidth: '100%',
              minHeight: '100%',
              position: 'absolute',
              top: 0,
              left: '50%',
              transform: 'translateX(-50%)',
            },
            '& .image--state': {
              display: 'flex',
              flexDirection: 'column',
              justifyContent: 'center',
              alignItems: 'center',
              color: '#999',
              background: '#eee',
              width: '100%',
              height: '100%',
            },
            '& .image--img': {
              opacity: 0,
              visibility: 'hidden',
            },
            '& .image--icon': {
              fontSize: 30,
              maxWidth: '80%',
              maxHeight: '80%',
            },
          },
        },
        rest.sx
      )}>
      <div className={`image ${className} ${classes.root}`} style={mergedStyle}>
        {(fallbackError || (!fallbackSrc && imgState === 'error')) && (
          <div className="image--state" title="Image load error">
            <Icon icon={WarningRoundedIcon} className="image--icon" />
          </div>
        )}
        {!placeholder && imgState === 'loading' && (
          <div className="image--state" title="loading image">
            <Icon icon={ImageRoundedIcon} className="image--icon" />
          </div>
        )}
        {imgState === 'loaded' && <img className="image--img" src={src} alt={alt} />}
      </div>
    </Box>
  );
}

Img.propTypes = {
  src: PropTypes.string.isRequired,
  alt: PropTypes.string,
  size: PropTypes.string,
  position: PropTypes.string,
  style: PropTypes.object,
  ratio: PropTypes.number,
  repeat: PropTypes.string,
  width: PropTypes.number,
  height: PropTypes.number,
  lazy: PropTypes.bool,
  placeholder: PropTypes.string,
  fallback: PropTypes.string,
  className: PropTypes.string,
  onError: PropTypes.func,
  onSuccess: PropTypes.func,
  useProxyFallback: PropTypes.bool,
};

export default Img;
