/* eslint-disable react-hooks/exhaustive-deps */
import React, { useEffect } from 'react';
import PropTypes from 'prop-types';

const ScrollX = ({
  children,
  refTag = {},
  scroll = false,
  stopScrolling = () => {},
  onScroll = () => {},
}) => {
  let pos = { top: 0, left: 0, x: 0, y: 0 };

  const preventDefaultEvents = (e) => {
    e.preventDefault();
  };

  const mouseMoveHandler = (e) => {
    const dx = e.clientX - pos.x;
    refTag.current.scrollLeft = pos.left - dx;
  };

  const mouseUp = (e) => {
    refTag.current.style.cursor = 'grab';
    refTag.current.style.removeProperty('user-select');

    const deltaX = e.clientX - pos.x;
    const deltaY = e.clientY - pos.top;
    const euclidean = Math.sqrt(deltaX * deltaX + deltaY * deltaY);

    if (euclidean < 5) {
      e.target.removeEventListener('click', preventDefaultEvents);
    } else {
      e.target.addEventListener('click', preventDefaultEvents);
    }

    refTag.current.removeEventListener('mousemove', mouseMoveHandler);
    refTag.current.removeEventListener('mouseup', mouseUp);
    refTag.current.removeEventListener('mouseleave', mouseUp);

    stopScrolling();
  };

  const mouseDown = (e) => {
    refTag.current.style.cursor = 'grabbing';
    refTag.current.style.userSelect = 'none';

    pos = {
      left: refTag.current.scrollLeft,
      x: e.clientX,
      top: e.clientY,
    };

    e.target.addEventListener('dragstart', (e) => {
      e.preventDefault();
    });

    refTag.current.addEventListener('mousemove', mouseMoveHandler);
    refTag.current.addEventListener('mouseup', mouseUp);
    refTag.current.addEventListener('mouseleave', mouseUp);
  };

  const handleScroll = () => {
    onScroll(refTag.current.scrollLeft);
  };

  useEffect(() => {
    if (scroll) {
      refTag.current.style.cursor = 'grab';
      refTag.current.addEventListener('mousedown', mouseDown);
      refTag.current.addEventListener('scroll', handleScroll);
    }

    return () => {
      refTag.current?.removeEventListener('mousedown', mouseDown);
      refTag.current?.removeEventListener('scroll', handleScroll);
    };
  }, [scroll]);

  return <>{children}</>;
};

ScrollX.propTypes = {
  children: PropTypes.node,
  refTag: PropTypes.shape({}),
  scroll: PropTypes.bool,
  onScroll: PropTypes.func,
  stopScrolling: PropTypes.func,
};

export default ScrollX;
