'use client';

import React from 'react';
import { CDNOptions } from '../types';
import NextImage, { ImageProps as NextImageProps } from 'next/image';
import { twMerge } from 'tailwind-merge';
import { ImageLoader } from '../utils/image-loader';

interface ImageProps extends NextImageProps {
  /**
   * Use fill to make the image responsive.
   * You also need to provide sizes and aspectRatio props.
   *
   * @default false
   */
  fill?: boolean;
  /**
   * Crop option for CDN
   *
   * Available options:
   * - `center`
   * - `top`
   * - `bottom`
   * - `left`
   * - `right`
   *
   * @default 'center'
   */
  crop?: CDNOptions['crop'];
  /**
   * It is used to calculate the height of the image when fill is true.
   * It prevents layout shift problems.
   */
  aspectRatio?: number;
  /**
   * Sizes attribute for responsive images
   *
   * If it is not provided, large images will be downloaded for small screens and it will cause performance issues.
   *
   * @example
   * <Image
   *  src={src}
   *  sizes="(min-width: 768px) 50vw, 100vw"
   *  fill
   * />
   * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#attr-sizes
   */
  sizes?: string;
  imageClassName?: string;

  /**
   * Swiper removed and we use react-multi-carousel at the moment.
   * We need to use this prop to make the image draggable or not.
   */
  draggable?: boolean;
}

const DEFAULT_QUALITY = 70;

/**
 * Image component for responsive images.
 *
 * It uses CDN options automatically if the image is hosted on Akinon CDN. You don't need to convert the src prop to CDN url.
 *
 * ## For responsive images
 * You need to provide `fill`, `sizes` and `aspectRatio` props.
 * If you are not sure about sizes, you can give `100vw` as a value. But it may cause performance issues.
 *
 * ## For non-responsive images
 * You need to provide `width` and `height` props.
 * This way, the browser will know the size of the image before downloading it and it will prevent layout shift problems.
 *
 * ## CDN options
 * You can use `crop` option to crop the image.
 *
 * Available options:
 * - `center`
 * - `top`
 * - `bottom`
 * - `left`
 * - `right`
 *
 * You can also use `quality` option to change the quality of the image.
 * Be careful about the file size when you change the quality.
 *
 * @default 70
 */
export const Image = (props: ImageProps) => {
  const {
    src,
    width,
    fill,
    sizes,
    aspectRatio,
    quality = DEFAULT_QUALITY,
    crop = 'center',
    draggable,
    className,
    imageClassName,
    ...restImage
  } = props;

  const optimizeImageURL = ({ src, width }) => {
    return ImageLoader({
      src,
      width,
      quality: parseInt(String(quality), DEFAULT_QUALITY),
      crop,
      fill,
      aspectRatio
    });
  };

  const hasGif = typeof src === 'string' && src.includes('.gif');

  if (fill && !aspectRatio) {
    throw new Error('aspectRatio is required when fill is true');
  }

  if (fill && !sizes) {
    throw new Error('sizes is required when fill is true');
  }

  return (
    <div
      className={twMerge('relative inline-block', fill && 'w-full', className)}
      style={{
        ...(fill && { aspectRatio })
      }}
    >
      <NextImage
        {...restImage}
        width={width}
        src={optimizeImageURL({ src, width })}
        sizes={sizes}
        fill={fill}
        loader={({ src, width }) => optimizeImageURL({ src, width })}
        className={imageClassName}
        {...(hasGif && { unoptimized: true })}
        {...(draggable !== undefined && { draggable })}
      />
    </div>
  );
};
