import * as seadn from "@opensea/seadn"
import { CenterAligned, classNames, Flex } from "@opensea/ui-kit"
import { Image as ImageIcon } from "@opensea/ui-kit/icons"
import NextImage from "next/image"
import React, { forwardRef } from "react"
import { blurhashToBase64 } from "./blurhash"

type NextImageProps = React.ComponentProps<typeof NextImage>

export type ImageProps = Omit<NextImageProps, "alt" | "src" | "blurDataURL"> & {
  alt?: string
  src: string | null | undefined
  /* Fit for the media optimisation. This does not influence the html element's object-fit which is a separate property */
  fit?: seadn.MediaFit
  frameTime?: number
  format?: seadn.MediaFormat
  blurhash?: string | null
  /**
   * This can be useful for cases where we have the blurDataURL already computed
   */
  blurDataURL?: string | null
  original?: boolean
  /**
   * Boost the image quality by going to the next image bucket. E.g. boost=2 will go up one bucket.
   */
  boost?: number
}

export const Image = forwardRef<HTMLImageElement, ImageProps>(function Image(
  {
    original,
    src,
    unoptimized,
    blurhash,
    alt = "",
    fit,
    frameTime,
    boost,
    format,
    blurDataURL: blurDataURLProp,
    ...rest
  },
  ref,
) {
  if (!src) {
    const height = Number(rest.height?.toString().replace("px", "") ?? 0)
    const width = Number(rest.width?.toString().replace("px", "") ?? 0)
    const smallestSide = Math.min(height, width)
    const size = smallestSide <= 100 ? "50%" : "20%"

    return (
      <Flex
        className={classNames("relative bg-bg-additional-2", rest.className)}
      >
        <CenterAligned
          className={classNames("absolute left-0 top-0 size-full")}
        >
          <ImageIcon size={size} />
        </CenterAligned>

        {/* Placeholder image to maintain sizing */}
        <NextImage
          {...rest}
          alt={alt}
          ref={ref}
          // inline transparent png
          src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII="
          unoptimized={unoptimized}
        />
      </Flex>
    )
  }

  const blurDataURL =
    blurDataURLProp ?? (blurhash ? blurhashToBase64(blurhash) : undefined)
  const placeholder = blurDataURL ? "blur" : undefined

  // if we have no dimensions, let the NextJS srcset logic kicking and we might resize
  // via loader
  if (
    original !== true &&
    (typeof src !== "string" || (!rest.height && !rest.width))
  ) {
    return (
      <NextImage
        {...rest}
        alt={alt}
        blurDataURL={blurDataURL}
        placeholder={placeholder}
        ref={ref}
        src={src}
        unoptimized={unoptimized}
      />
    )
  }

  const resized = original
    ? seadn.originalURL(src)
    : seadn.optimize(src, {
        height: rest.height,
        width: rest.width,
        quality: rest.quality,
        fit,
        frameTime,
        boost,
        format,
      })

  return (
    <NextImage
      {...rest}
      {...(!rest.height || !rest.width
        ? { fill: true, width: undefined, height: undefined }
        : { height: rest.height, width: rest.width })}
      alt={alt}
      blurDataURL={blurDataURL}
      placeholder={placeholder}
      ref={ref}
      src={resized}
      // we are resizing the image via src, and skipping the nextjs loader & srcset logic as they are redundant
      unoptimized={unoptimized ?? true}
    />
  )
})
