import { useMemo, useState, useRef } from 'react';
import { AnyD3Scale } from '@visx/scale';
import { localPoint } from '@visx/event';
import { Group } from '@visx/group';

import { VerticalLine } from './VerticalLine';
import { TooltipSetter } from '../hooks/useTooltip';

function toArray<T>(obj: T) {
  return obj ? (Array.isArray(obj) ? (obj as T[]) : [obj]) : [];
}

interface MouseMoveHandlerProps {
  width: number;
  height: number;
  top: number;
  left: number;
  data: any[];
  xScale: AnyD3Scale;
  yScale: (datum: any) => number;
  onHover: TooltipSetter;
}

export const MouseMoveHandler = ({
  width,
  height,
  top,
  left,
  data,
  xScale,
  yScale,
  onHover,
}: MouseMoveHandlerProps) => {
  const [offset, setOffset] = useState<{ x: number; y: number } | null>(null);
  const indexRef = useRef<number | null>(null);

  const handleMouseMove: React.MouseEventHandler<SVGRectElement> = (ev) => {
    ev.persist();
    const point = localPoint(ev);
    if (point === null) return;
    let x = point.x - left;

    // @ts-ignore
    const index = Math.round(xScale.invert(x));

    if (indexRef.current !== index) {
      indexRef.current = index;

      const datum = data[index];

      const offsetX = (width / (data.length - 1)) * index;
      const offsetY = typeof yScale === 'function' ? yScale(datum) : 0;

      onHover({ data: datum, top: ev.clientY, left: ev.clientX });
      setOffset({ x: offsetX, y: offsetY });
    }
  };

  const handleMouseLeave = () => {
    indexRef.current = null;
    onHover(null);
    setOffset(null);
  };

  const currentItem = indexRef.current;

  const points = useMemo(() => {
    const datum = currentItem !== null ? toArray(data[currentItem]) : [];

    return datum.map((datum) => {
      const offsetY = typeof yScale === 'function' ? yScale(datum) : 0;
      return offsetY;
    });
  }, [data, currentItem]);

  return (
    <Group top={top} left={left}>
      {offset !== null && (
        <VerticalLine height={height} offsetX={offset?.x} points={points} />
      )}
      <rect
        width={width}
        height={height}
        fill="transparent"
        // onMouseEnter={handleMouseEnter}
        onMouseMove={handleMouseMove}
        onMouseLeave={handleMouseLeave}
      />
    </Group>
  );
};
