"use strict";

// const React = require("react");
const euclideanDistance = require("euclidean-distance");
const throttleit = require("throttleit");
// const useForceUpdate = require("use-force-update");

/* CAUTION: This hook has a bunch of effectively-global state! This is fine since a) there can only ever be one drag operation on a document at a time anyway, and b) this appears to be necessary to sidestep performance limitations introduced by React's state-handling cycles, but it's definitely something you shouldn't normally do. */

let operationData;
let isDragging;
let lastMouseX;
let lastMouseY;
let newX;
let newY;
let onChangeCallback;
let thresholdMet = false;
let dragThreshold;

function getCurrentValues() {
	return {
		x: operationData.initialValueX + (lastMouseX - operationData.initialMouseX),
		y: operationData.initialValueY + (lastMouseY - operationData.initialMouseY)
	};
}

let processMouseMove = throttleit(() => {
	/* Yes, the below check is there for a reason; just in case the `movingWindow` state changes between the call to the throttled wrapper and the wrapped function itself. */
	if (onChangeCallback != null) {
		if (thresholdMet === false) {
			let origin = [operationData.initialMouseX, operationData.initialMouseY];
			let position = [lastMouseX, lastMouseY];

			if (euclideanDistance(origin, position) > dragThreshold) {
				thresholdMet = true;
			}
		}

		if (thresholdMet === true) {
			let {x, y} = getCurrentValues();
			newX = x;
			newY = y;
			onChangeCallback(x, y, lastMouseX, lastMouseY);
		}
	}
}, 10);

module.exports = {
	mouseMove: function (x, y) {
		/* NOTE: Due to how synthetic events work in React, we need to separate out the 'get coordinates from event' and 'do something with the coordinates' step; if we throttle the coordinate extraction logic, we'll run into problems when synthetic events have already been cleared for reuse by the time we try to obtain the coordinates. Therefore, `processMouseMove` contains all the throttled logic, whereas the coordinate extraction happens on *every* mousemove event. */
		lastMouseX = x;
		lastMouseY = y;

		if (isDragging) {
			processMouseMove();
		}
	},
	useDraggable: function (options) {
		let dragEnded = false;
		let dragStarted = false;

		if (isDragging === true && options.isDragging === false) {
			dragEnded = true;
		} else if (isDragging === false && options.isDragging === true) {
			dragStarted = true;
		}

		operationData = options.operationData;
		dragThreshold = options.threshold;
		onChangeCallback = options.onChange;
		isDragging = options.isDragging;

		if (dragStarted) {
			processMouseMove();
		}

		if (dragEnded) {
			return [newX, newY];
		} else {
			return [null, null];
		}
	}
};
