import react, { useState } from 'react';
import Viewport from './Viewport';

interface MouseHandlerProperties {
  boardSize: number;
  shift: { x: number; y: number };
  zoom: number;
}

const MouseHandler: react.FC<MouseHandlerProperties> = (
  props: MouseHandlerProperties
) => {
  const initialMouseState = {
    down: false,
    starting: { x: -1, y: -1 },
    timestamp: 0,
  };

  const [mouseState, setMouseState] = useState(initialMouseState);

  const [shift, setShift] = useState(props.shift);
  const [zoom, setZoom] = useState(props.zoom);

  console.log('MouseHandler, mouseState: ' + JSON.stringify(mouseState));
  console.log(
    'MouseHandler, shift: ' + JSON.stringify(shift) + ', zoom:' + zoom
  );

  const genericHandler = (event: any) => {
    console.log(`Log - Event:  ${event.type}`);
    if (event.pageX !== undefined) {
      console.log(
        `Mouse : ${event.pageX}, ${event.pageY}, target: ${event.target}`
      );
      console.log(
        `mouseState: ' ${JSON.stringify(mouseState)} (+${
          Date.now() - mouseState.timestamp
        }ms) `
      );
      return;
    }
  };

  const mouseLeaveHandler = (event: any) => {
    genericHandler(event);
    setMouseState(initialMouseState);
  };

  const mouseDownHandler = (event: any) => {
    genericHandler(event);
    setMouseState({
      down: true,
      starting: { x: event.pageX, y: event.pageY },
      timestamp: Date.now(),
    });
  };

  const mouseUpHandler = (event: any) => {
    genericHandler(event);
    setMouseState(initialMouseState);
  };

  const mouseMoveHandler = (event: any) => {
    if (mouseState.down && Date.now() - mouseState.timestamp > 5) {
      genericHandler(event);
      console.log(
        `dispatch ${JSON.stringify({
          x: event.pageX - mouseState.starting.x,
          y: event.pageY - mouseState.starting.y,
        })}`
      );
      setShift({
        x: shift.x + (event.pageX - mouseState.starting.x),
        y: shift.y + (event.pageY - mouseState.starting.y),
      });
      setMouseState({
        down: true,
        starting: {
          x: event.pageX,
          y: event.pageY,
        },
        timestamp: Date.now(),
      });
    }
  };

  const doScale = (x: number, y: number, factor: number) => {
    setShift({
      x: shift.x + (shift.x - x) * (factor - 1),
      y: shift.y + (shift.y - y) * (factor - 1),
    });
    setZoom(zoom * factor);
  };

  const doubleClickHandler = (event: any) => {
    genericHandler(event);
    doScale(event.pageX, event.pageY, Math.SQRT2);
  };

  const initialWheelState = {
    timestamp: 0,
  };

  const [wheelState, setWheelState] = useState(initialWheelState);

  const wheelEventHandler = (event: any) => {
    genericHandler(event);
    if (
      event.deltaMode === WheelEvent.DOM_DELTA_PIXEL &&
      Date.now() - wheelState.timestamp > 100
    ) {
      doScale(
        event.pageX,
        event.pageY,
        event.deltaY < 0 ? Math.SQRT2 : Math.SQRT1_2
      );

      setWheelState({
        timestamp: Date.now(),
      });
    }
  };

  return (
    <div
      onMouseDown={mouseDownHandler}
      onMouseMove={mouseMoveHandler}
      onMouseUp={mouseUpHandler}
      onMouseLeave={mouseLeaveHandler}
      onDoubleClick={doubleClickHandler}
      onWheel={wheelEventHandler}
    >
      <Viewport boardSize={props.boardSize} shift={shift} zoom={zoom} />
    </div>
  );
};

export default MouseHandler;
