import React, { Suspense } from "react";
import clsx from "clsx";
import { useImage } from "react-image";

import { makeStyles, createStyles } from "@mui/styles";
import Skeleton from "@mui/material/Skeleton";
import BrokenImageIcon from "@mui/icons-material/BrokenImageOutlined";

import ErrorBoundary from "./ErrorBoundary";

const useStyles = makeStyles((theme) =>
  createStyles({
    root: ({
      objectFit,
      shape,
      border,
    }: Pick<IThubmnailProps, "objectFit" | "shape" | "border">) => ({
      objectFit: objectFit as any,
      borderRadius:
        shape === "circle"
          ? "50%"
          : shape === "square"
          ? 0
          : theme.shape.borderRadius,

      display: "block",
      pointerEvents: "none",
      userSelect: "none",

      position: "relative",

      "&::after": {
        content: '""',
        display: "block",
        position: "absolute",
        top: 0,
        left: 0,
        width: "100%",
        height: "100%",

        boxShadow: border ? `0 0 0 1px ${theme.palette.divider} inset` : "none",
      },
    }),

    skeleton: ({ shape }: Pick<IThubmnailProps, "shape">) => ({
      borderRadius:
        shape === "circle"
          ? "50%"
          : shape === "square"
          ? 0
          : theme.shape.borderRadius,
      display: "block",
    }),
  })
);

export interface IThubmnailProps
  extends React.DetailedHTMLProps<
    React.ImgHTMLAttributes<HTMLImageElement>,
    HTMLImageElement
  > {
  imageUrl: string;
  size?: string;

  objectFit?: string;
  shape?: "roundedRectangle" | "square" | "circle";
  border?: boolean;
}

/**
 * Display a thumbnail generated by compressedThumbnail cloud function,
 * falling back to original image if it doesn’t load.
 *
 * Uses react-image: https://github.com/mbrevda/react-image
 */
export function Thubmnail_({
  imageUrl,
  size = "200x200",

  objectFit = "cover",
  shape = "roundedRectangle",
  border = false,

  ...props
}: IThubmnailProps) {
  const classes = useStyles({ objectFit, shape, border });

  // Add size suffix just before file name extension (e.g. .jpg)
  const thumbnailUrl = imageUrl.replace(
    /(\.[\w]+\?.*token=[\w-]+$)/,
    `__${size}$1`
  );

  const { src, error } = useImage({
    srcList: [thumbnailUrl, imageUrl],
  });

  if (error) return <>x</>;

  return (
    <img {...props} src={src} className={clsx(classes.root, props.className)} />
  );
}

/**
 * Wrap thumbnail in an ErrorBoundary and Skeleton for loading
 */
export default function Thumbnail(props: IThubmnailProps) {
  const classes = useStyles({ shape: props.shape });

  return (
    <ErrorBoundary
      basic
      message="Failed to load image"
      className={props.className}
      render={(m) => <BrokenImageIcon color="disabled" />}
    >
      <Suspense
        fallback={
          <Skeleton
            variant="rectangular"
            className={clsx(classes.skeleton, props.className)}
          />
        }
      >
        <Thubmnail_ {...props} />
      </Suspense>
    </ErrorBoundary>
  );
}
