import React, { Children, useCallback } from "react";
import { motion } from "framer-motion";

import { Grid } from "../grid";
import { Box } from "../box";

const ChildWrapper: React.FC<{
  children: React.ReactNode;
  childIndex: number;
  onFocus: (index: number) => void;
  firstElementRef: React.RefObject<HTMLDivElement>;
}> = ({ children, childIndex, firstElementRef, onFocus }) => {
  const onDragStart = useCallback((e: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
    e.preventDefault();
  }, []);

  const onFocusHandler = useCallback(() => {
    onFocus(childIndex);
  }, [childIndex, onFocus]);

  return (
    <Box>
      <Box
        style={{ width: "fit-content", height: "100%" }}
        {...(childIndex === 0 && { ref: firstElementRef })}
        onFocus={onFocusHandler}
        onDragStart={onDragStart}
      >
        {children}
      </Box>
    </Box>
  );
};

interface Props extends Omit<React.ComponentProps<typeof Grid>, "columns" | "onDragEnd"> {
  viewWindowHeight: number;
  viewWindowWidth: number;
  gridWidth: number;
  gridX: number;
  rows: number;
  children: Array<React.ReactElement>;
  firstElementRef: React.RefObject<HTMLDivElement>;
  transition?: React.ComponentProps<typeof motion.div>["transition"];
  onDragEnd: React.ComponentProps<typeof motion.div>["onDragEnd"];
  onItemFocus: (index: number) => void;
  disableDrag: boolean;
}

// eslint-disable-next-line max-lines-per-function
export const BaseCarousel: React.FC<Props> = ({
  viewWindowHeight,
  viewWindowWidth,
  gridWidth,
  gridX,
  rows,
  children,
  firstElementRef,
  transition = { type: "spring", stiffness: 300, damping: 30 },
  onItemFocus,
  onDragEnd,
  onMouseDown,
  onMouseUp,
  disableDrag,
  ...gridProps
}) => {
  const onScroll: React.UIEventHandler<HTMLDivElement> = useCallback((e) => {
    e.currentTarget.scrollLeft = 0;
  }, []);

  return (
    <Box
      style={{
        height: viewWindowHeight,
        width: viewWindowWidth,
        overflow: "hidden",
      }}
      onScroll={onScroll}
    >
      <motion.div
        {...(!disableDrag && { drag: "x" })}
        animate={{ x: gridX }}
        transition={{
          x: transition,
        }}
        onMouseDown={onMouseDown}
        onMouseUp={onMouseUp}
        onDragEnd={onDragEnd}
        style={{ width: gridWidth }}
      >
        <Grid
          {...gridProps}
          css={{
            ...gridProps.css,
            gridTemplateRows: `repeat(${rows}, auto)`,
            gridAutoFlow: "column",
          }}
          data-grid
        >
          {Children.map(children, (child, i) => {
            return (
              <ChildWrapper
                key={child.key}
                firstElementRef={firstElementRef}
                childIndex={i}
                onFocus={onItemFocus}
              >
                {child}
              </ChildWrapper>
            );
          })}
        </Grid>
      </motion.div>
    </Box>
  );
};
