import {
  FC,
  useEffect,
  useState,
  type MouseEvent as ReactMouseEvent,
  type SyntheticEvent,
} from 'react';

import CardMedia from '@material-hu/mui/CardMedia';

import { Attachment } from 'src/types/attachments';
import { File } from 'src/types/files';
import {
  getImageDimensions,
  getMaxHeightCardContent,
} from 'src/utils/attachments';

export type MediaBaseProps = {
  media?: Partial<Attachment | File>;
  hasZoom?: boolean;
  onLoad?: () => void;
  onClick?: (event: ReactMouseEvent<HTMLImageElement, MouseEvent>) => void;
  mediaHeight?: number;
  mediaWidth?: number;
  isFilePreview?: boolean;
  initialZoom?: boolean;
};

const Image: FC<MediaBaseProps> = props => {
  const {
    media,
    mediaHeight = undefined,
    mediaWidth = undefined,
    onLoad = () => null,
    onClick = () => null,
    hasZoom = false,
    initialZoom = false,
  } = props;

  const [zoom, setZoom] = useState(false);
  const [mouseX, setMouseX] = useState(0);
  const [mouseY, setMouseY] = useState(0);
  const [isMediaLoading, setIsMediaLoading] = useState(true);
  const [naturalWidth, setNaturalWidth] = useState<number | null>(null);
  const [naturalHeight, setNaturalHeight] = useState<number | null>(null);

  useEffect(() => {
    setZoom(false);
  }, [media?.name]);

  const handleClick = (
    event: ReactMouseEvent<HTMLImageElement, MouseEvent>,
  ) => {
    if (hasZoom) {
      setZoom(!zoom);
    }
    onClick(event);
  };

  const handleMouseMove = (
    e: ReactMouseEvent<HTMLImageElement, MouseEvent>,
  ) => {
    if (!zoom) return;
    const rect = e.currentTarget.getBoundingClientRect();
    const x = e.pageX - rect.left;
    const y = e.pageY - rect.top;
    setMouseX(x);
    setMouseY(y);
  };

  let url = undefined,
    source = undefined,
    name = undefined,
    width = undefined,
    height = undefined;
  if (media) {
    name = media?.name;
    source =
      'source' in media ? ((media as File).source ?? undefined) : undefined;
    url = 'url' in media ? (media as Attachment).url : undefined;
    width = 'width' in media ? (media as Attachment).width : undefined;
    height = 'height' in media ? (media as Attachment).height : undefined;
  }

  let imageCursor = 'auto';
  if (hasZoom) {
    if (zoom) {
      imageCursor = 'zoom-out';
    } else {
      imageCursor = 'zoom-in';
    }
  }

  const transformImage = `translate(-${mouseX / 10}px, -${mouseY / 10}px)`;

  const handleOnLoad = (e: SyntheticEvent<HTMLImageElement, Event>) => {
    const target = e.currentTarget as HTMLImageElement;
    if (
      target?.naturalWidth &&
      target?.naturalHeight &&
      !naturalWidth &&
      !naturalHeight
    ) {
      setNaturalWidth(target.naturalWidth);
      setNaturalHeight(target.naturalHeight);
    }
    setIsMediaLoading(false);
    onLoad();
  };

  const { imageWidth, imageHeight } = getImageDimensions({
    isMediaLoading,
    zoom,
    mediaWidth: mediaWidth || naturalWidth,
    mediaHeight: mediaHeight || naturalHeight,
    width: width || naturalWidth,
    height: height || naturalHeight,
    initialZoom,
  });

  const maxHeight = getMaxHeightCardContent(zoom);

  return (
    <>
      <CardMedia
        src={url || source}
        component="img"
        loading="lazy"
        onLoad={handleOnLoad}
        onClick={handleClick}
        onMouseMove={handleMouseMove}
        alt={name}
        width={imageWidth}
        height={imageHeight}
        sx={{
          cursor: imageCursor,
          backgroundPosition: 'top',
          maxHeight: maxHeight,
          maxWidth: initialZoom ? '100%!important' : 'none!important',
          objectFit: 'contain',
          transform: zoom ? transformImage : 'none',
          width: 'fit-content',
        }}
      />
    </>
  );
};

export default Image;
