import React, { FC, forwardRef, memo, Suspense, useMemo } from 'react';
import { createAsset }                                    from 'use-asset';
import { cn }                                             from '../../util/bem';
import { SizeType }                                       from '../../util/global-props';
import { loadImage }                                      from '../../util/loadImage';
import { Image }                                          from '../img/img.component';
import { Lottie }                                         from '../lottie/lottie.component';
import './media.component.scss';

export type MediaComponentPropsType = {
  className?: string;
  url?: string;
  animationData?: { [key: string]: any };
  autoplay?: boolean;
  loop?: boolean;
  play?: boolean;
  placeholder?: string;
  style?: React.CSSProperties;
  // only for animation
  speed?: number;
  playFrom?: number

  padding?: SizeType;
  align?: 'start' | 'center' | 'end';
  ratio?: 'auto' | 'full' | 'ratio-16-9' | 'ratio-4-3' | 'ratio-1-1' | 'ratio-3-4' | 'ratio-9-16';
  size?: SizeType;
  type?: 'animation' | 'image' | 'video';
  fit?: 'auto' | 'fit-content' | 'cover' | 'contain' | 'fill';

  styles?: React.CSSProperties;
  onClick?: React.EventHandler<React.MouseEvent<HTMLDivElement, PointerEvent>>;
  onMouseDown?: React.EventHandler<React.MouseEvent<HTMLDivElement, PointerEvent>>;
  onMouseLeave?: React.EventHandler<React.MouseEvent<HTMLDivElement>>;
  onMouseEnter?: React.EventHandler<React.MouseEvent<HTMLDivElement>>;
};

const loadedImage = createAsset(async (url) => loadImage(url));

const className = cn('media');

const Media = memo(forwardRef<HTMLDivElement, MediaComponentPropsType>((props, ref: React.Ref<HTMLDivElement>) => {
    const {
        url,
        autoplay,
        loop,
        play,
        placeholder,
        speed,
        playFrom,
        align,
        ratio,
        size,
        type,
        fit,
        styles,
        style,
        padding,
        onClick,
        onMouseDown,
        onMouseLeave,
        onMouseEnter,
        animationData

    } = props;
    const processedUrl = type === 'image' ? loadedImage.read(url) : url;
    const content = useMemo(() => {
        switch (props.type) {
            case 'animation':
                return (
                    <Lottie
                        className={ placeholder ? className('hasPlaceholder', { hide: !play }) : '' }
                        speed={ speed }
                        autoplay={ autoplay }
                        loop={ loop }
                        start={ play }
                        src={ !animationData ? processedUrl : undefined }
                        animationData={ animationData }
                        playFrom={ playFrom }
                    />
                );
            case 'video':
            case 'image':
                return (
                    <>
                        { processedUrl && (
                            <Image alt="" src={ processedUrl } />
                        ) }
                        { !processedUrl && !!placeholder && (
                            <Image alt="" src={ placeholder } />
                        ) }
                    </>
                );
            default:
                return null;
        }
    }, [ processedUrl, autoplay, loop, play, placeholder, speed, playFrom, type ]);
    return (
        <div
            className={ className({
                fit, size, padding, hasPlaceholder: !!placeholder, align, ratio
            }) }
            ref={ ref }
            onClick={ onClick }
            onMouseEnter={ onMouseEnter }
            onMouseLeave={ onMouseLeave }
            onMouseDown={ onMouseDown }
            style={ { ...style, ...styles } }
        >
            { (type === 'animation' || type === 'video') && placeholder ? (
                <Image className={ className('image-placeholder', { hide: play }) } src={ placeholder } alt="" />
            ) : null }
            { content }
        </div>
    );
}));

Media.displayName = 'Media';

export const MediaContent: FC<MediaComponentPropsType> = memo(forwardRef<HTMLDivElement, MediaComponentPropsType>((props, ref) => (
    <Suspense fallback={ null }>
        <Media { ...props } ref={ ref } />
    </Suspense>
)));
