'use client';

import 'lazysizes';
import { ImageProps } from 'next/image';
import { memo, useCallback, useEffect, useMemo, useState } from 'react';

import { FALLBACK_IMAGE_URL } from '@/utils/constants';

// from the resize lambda
// https://github.com/suno-ai/glockenspiel/blob/d0d4d6d0f13ee83e767a44162ed5b9fdd9dd88f2/studio_api/lambda_functions/cloudfront-api-gateway-image-processor/lambda_function.py#L29
export enum ImageSize {
  SMALL = 100,
  LARGE = 360,
  XLARGE = 720,
  ORIGINAL = 1024,
}

const IMAGE_SIZES = [
  ImageSize.SMALL,
  ImageSize.LARGE,
  ImageSize.XLARGE,
  ImageSize.ORIGINAL,
];

// TODO: enforce these stricter types be explicit in ImageWithFallback
// export type Props = Omit<ImageProps, 'src'> &
//   (
//     | {
//         src?: string | null;
//         fallbackSrc?: string;
//         imageSize: ImageSize;
//       }
//     | {
//         src: `/${string}`;
//         fallbackSrc?: string;
//         imageSize?: never;
//       }
//     | {
//         src: string;
//         fallbackSrc?: string;
//         imageSize: ImageSize;
//       }
//   );
export interface Props extends Omit<ImageProps, 'src'> {
  src?: string | null;
  fallbackSrc?: string;
  imageSize?: ImageSize;
}

function getJpegLink({
  src,
  imageSize,
}: {
  src: string;
  imageSize: ImageSize;
}) {
  if (imageSize == ImageSize.ORIGINAL) {
    return getOriginalImage(src);
  }
  if (
    src != FALLBACK_IMAGE_URL &&
    src?.endsWith('.jpeg') &&
    IMAGE_SIZES.includes(imageSize)
  ) {
    return src + '?width=' + imageSize;
  }
  return src;
}

export function getOriginalImage(src: string | undefined) {
  if (src != FALLBACK_IMAGE_URL && src?.endsWith('.jpeg')) {
    if (src.includes('image')) {
      src = src.replace('image', 'image_large');
      return src;
    }
  }
  return src;
}

const ImageWithFallback: React.FC<Props> = memo(function ImageWithFallback({
  alt,
  src,
  fallbackSrc = FALLBACK_IMAGE_URL,
  imageSize = 0,
  ...restProps
}) {
  const [imageSrc, setImageSrc] = useState<string>(src || fallbackSrc);

  const handleFallback = useCallback(() => {
    if (fallbackSrc && imageSrc !== fallbackSrc) {
      setImageSrc(fallbackSrc);
    }
  }, [fallbackSrc, imageSrc]);

  useEffect(() => {
    setImageSrc(src || fallbackSrc);
  }, [src, fallbackSrc]);

  const effectiveImageSrc = useMemo(
    () =>
      imageSize && IMAGE_SIZES.includes(imageSize)
        ? getJpegLink({ src: imageSrc, imageSize })
        : imageSrc,
    [imageSrc, imageSize]
  );

  const dataSrc = useMemo(() => getOriginalImage(src || undefined), [src]);

  return (
    // eslint-disable-next-line @next/next/no-img-element
    <img
      alt={alt}
      src={effectiveImageSrc || ''}
      data-src={dataSrc}
      onError={handleFallback}
      {...restProps}
    />
  );
});

export default ImageWithFallback;
