import { blurhashToImageCssObject } from "@unpic/placeholder";
import * as React from "react";
import { transformUrl } from "unpic";
import { useDebugEvents } from "../../utils";
import { TooltipSymbol } from "../Tooltip";
import * as styles from "./styles.module.css";

const configDeviceSizes = [
  480, // old phones
  640, // older and lower-end phones
  750, // iPhone 6-8
  828, // iPhone XR/11
  960, // older horizontal phones
  1080, // iPhone 6-8 Plus
  1280, // 720p
  1668, // Various iPads
  1920, // 1080p
  2048, // QXGA
  2560, // WQXGA
  3200, // QHD+
  3840, // 4K
  4480, // 4.5K
  5120, // 5K
  6016, // 6K
];
const configImageSizes = [16, 32, 64, 128, 256];
const allSizes = [...configImageSizes, ...configDeviceSizes];

export type SrcContext = {
  src: string;
  height?: number;
  width?: number;
  blurhash?: string;
  dominantColor?: string;
};
export const Image = React.forwardRef(function Image(
  {
    image,
    altText,
    critical,
    omitBlurhash,
    sizes = "100vw",
    crossOrigin,
    ...rest
  }: {
    image: string | SrcContext;
    omitBlurhash?: boolean;
    altText: string;
    critical?: boolean;
    sizes: string;
    className: string;
    crossOrigin?: boolean;
    "data-id": string;
    "data-label"?: string;
  } & React.ImgHTMLAttributes<HTMLImageElement>,
  ref: React.ForwardedRef<HTMLImageElement>,
) {
  const [hasError, setHasError] = React.useState(false);
  const [hasLoaded, setHasLoaded] = React.useState(false);
  const attrs = useDebugEvents(rest);
  const src = typeof image === "string" ? image : image?.src;
  const width = typeof image === "string" ? undefined : image?.width;
  const height = typeof image === "string" ? undefined : image?.height;
  const blurhash = typeof image === "string" ? undefined : image?.blurhash;
  const dominantColor =
    typeof image === "string" ? undefined : image?.dominantColor;
  const aspectRatio = height && width ? height / width : undefined;
  const { hostname, pathname } = React.useMemo(
    () =>
      src
        ? src.startsWith("/")
          ? process.env.PREVIEW
            ? {
                pathname: src,
                fallbackPath: src,
                hostname: "__replace__",
              }
            : {
                pathname: `/cdn-cgi/image/f=auto${src}`,
                fallbackPath: src,
                hostname: "__replace__",
              }
          : new URL(src)
        : ({} as URL),
    [src],
  );

  const props: React.ImgHTMLAttributes<HTMLImageElement> = {
    src: src,
    width: width,
    height: height,
    sizes: sizes,
    onLoad: () => {
      setHasLoaded(true);
    },
  };

  if (altText) {
    props.alt = altText;
  } else {
    props.role = "presentation";
  }

  // if the customer doesn't pay for the image optimization service, we fallback to the original image
  if (
    pathname?.startsWith("/cdn-cgi/image/f=auto") ||
    hostname === "assets.devize.com" ||
    hostname === "assets.brevity.io"
  ) {
    props.onError = ({ currentTarget }) => {
      setHasLoaded(true);
      if (hasError) {
        return;
      }
      currentTarget.onerror = null;
      currentTarget.src = currentTarget.src.replace(
        /\/cdn-cgi\/image\/(.*?)\//g,
        "/",
      );
      currentTarget.srcset = "";
      currentTarget.sizes = "";
      setHasError(true);
    };
  }

  // High priority images should be loaded eagerly
  if (critical) {
    props.loading = "eager";
    (props as any).fetchPriority = "high";
  } else {
    // Otherwise use native lazy loading and async decoding
    props.loading = "lazy";
    props.decoding = "async";
  }

  if (hostname === "assets.devize.com" || hostname === "assets.brevity.io") {
    props.src = `https://assets.devize.com/cdn-cgi/image/f=auto${pathname}`;
    props.crossOrigin = "anonymous";
  }
  if (hostname === "__replace__") {
    props.crossOrigin = "anonymous";
  }

  if (props.src) {
    props.srcSet = allSizes
      .map((size) => {
        const transformed = transformUrl({
          url:
            hostname === "__replace__"
              ? `https://${hostname}${pathname}`
              : (props.src as string),
          width: size,
          height: aspectRatio ? Math.round(aspectRatio * size) : undefined,
        });
        if (transformed) {
          return `${transformed.toString()} ${size}w`;
        }
        return "";
      })
      .join(",\n")
      .replaceAll("https://__replace__", "");
  }

  if (crossOrigin) {
    props.crossOrigin = "anonymous";
  }

  if (blurhash && !hasLoaded && !omitBlurhash) {
    const blurStyles = blurhashToImageCssObject(blurhash, 7, 4);
    props.style = {
      ...blurStyles,
      ...props.style,
    };
  }
  if (dominantColor && !hasLoaded && !omitBlurhash) {
    props.style = {
      backgroundColor: dominantColor,
      ...props.style,
    };
  }

  return (
    <div className={styles.container}>
      {props.src ? (
        <img ref={ref} data-component="Image$Brevity" {...attrs} {...props} />
      ) : null}
    </div>
  );
});

Image[TooltipSymbol] = true;
