import React, { useMemo, useRef, useState } from 'react';
import { twMerge } from 'tailwind-merge';
import { useResizeObserver } from 'usehooks-ts';

export type FilmstripProps = {
  className?: string;
  style?: React.CSSProperties;
  src?: string;
  thumbnailColumns?: number;
  thumbnailRows?: number;
  thumbnailWidth: number;
  thumbnailHeight: number;
  thumbnailCount: number;
};

export type Props = Omit<
  React.HTMLAttributes<HTMLDivElement>,
  keyof FilmstripProps
> &
  FilmstripProps;

const Filmstrip: React.FC<Props> = (props) => {
  const {
    children,
    className,
    style,
    src,
    thumbnailCount,
    thumbnailColumns = thumbnailCount,
    thumbnailRows = Math.ceil(thumbnailCount / thumbnailColumns),
    thumbnailWidth,
    thumbnailHeight,
    ...restProps
  } = props;

  const ref = useRef<HTMLDivElement>(null);

  const [[filmstripWidth, filmstripHeight], setFilmstripSize] = useState([
    0, 0,
  ]);

  useResizeObserver({
    ref: ref as React.RefObject<HTMLDivElement>, // https://github.com/juliencrn/usehooks-ts/pull/675
    onResize() {
      if (ref.current) {
        setFilmstripSize([ref.current.clientWidth, ref.current.clientHeight]);
      }
    },
  });

  const thumbnails = useMemo(() => {
    const thumbnailDisplayWidth =
      (filmstripHeight * thumbnailWidth) / thumbnailHeight;
    const count = thumbnailDisplayWidth
      ? Math.ceil(filmstripWidth / thumbnailDisplayWidth)
      : 1;
    return new Array(count).fill(0).map((_v, i) => {
      const index = Math.floor(((thumbnailCount - 1) * i) / (count - 1));
      return {
        index: i,
        x: index % thumbnailColumns,
        y: Math.floor(index / thumbnailColumns),
      };
    });
  }, [
    filmstripWidth,
    filmstripHeight,
    thumbnailWidth,
    thumbnailHeight,
    thumbnailColumns,
    thumbnailCount,
  ]);

  return (
    <div
      className={twMerge(
        'relative flex flex-row items-stretch justify-stretch',
        className
      )}
      style={
        {
          ...style,
          '--filmstrip-width': `${filmstripWidth}px`,
          '--filmstrip-count': thumbnails.length,
          '--filmstrip-cols': thumbnailColumns,
          '--filmstrip-rows': thumbnailRows,
          '--filmstrip-thumb-width': `${Math.round(
            (filmstripHeight * thumbnailWidth) / thumbnailHeight
          )}px`,
          '--filmstrip-thumb-height': `${filmstripHeight}px`,
          '--filmstrip-thumb-crop-x':
            'calc(var(--filmstrip-thumb-width) - var(--filmstrip-width) / var(--filmstrip-count))',
          '--filmstrip-thumb-crop-y': '0px',
        } as React.CSSProperties
      }
      ref={ref}
      {...restProps}
    >
      {thumbnails.map(({ index, x, y }) => (
        <div
          data-key={index}
          data-thumb={`${x}, ${y}`}
          key={index}
          className='relative flex-1 bg-no-repeat'
          style={
            {
              '--filmstrip-sprite-x': x,
              '--filmstrip-sprite-y': y,
              backgroundImage: `url(${src})`,
              backgroundPosition: [
                `calc(-1 * var(--filmstrip-sprite-x) * var(--filmstrip-thumb-width) - 0.5 * var(--filmstrip-thumb-crop-x))`,
                `calc(-1 * var(--filmstrip-sprite-y) * var(--filmstrip-thumb-height) - 0.5 * var(--filmstrip-thumb-crop-y))`,
              ].join(' '),
              backgroundSize: 'auto calc(var(--filmstrip-rows) * 100%)',
            } as React.CSSProperties
          }
        />
      ))}
    </div>
  );
};

export default Filmstrip;
