import { ref, onMounted, onUnmounted, nextTick } from "vue";

export const useDragBox = () => {
	const dragBox = ref({
		top: 0,
		left: 0,
		pos1: 0,
		pos2: 0,
		pos3: 0,
		pos4: 0,
		width: 400,
		height: 50,
		initial: {
			top: 0,
			left: 0
		},
		latest: {
			top: null,
			left: null
		},
		debounceTimeout: null,
		lastTappedDate: 0
	});

	const onDragBoxUpdate = ref();

	const setOnDragBoxUpdate = newOnDragBoxUpdate => {
		onDragBoxUpdate.value = newOnDragBoxUpdate;
	};

	const setInitialBox = (initial, reset = false) => {
		dragBox.value.initial = initial || dragBox.value.initial;
		if (reset)
			dragBox.value = { ...dragBox.value, ...dragBox.value.initial };
	};

	const resetBoxPosition = (preventUpdate = false) => {
		setInitialBox(null, true);
		dragBox.value.latest.top = dragBox.value.top;
		dragBox.value.latest.left = dragBox.value.left;
		if (!preventUpdate && typeof onDragBoxUpdate.value === "function")
			onDragBoxUpdate.value();
	};

	const onDragBox = e => {
		const e1 = e || window.event;
		const e1IsTouch = e1.type === "touchstart";
		e1.preventDefault();

		if (e1IsTouch) {
			// Handle double click from touch (if this method is twice in a row within one second)
			if (Date.now() - dragBox.value.lastTappedDate <= 1000) {
				resetBoxPosition();
				dragBox.value.lastTappedDate = 0;
				return;
			}
			dragBox.value.lastTappedDate = Date.now();
		}

		dragBox.value.pos3 = e1IsTouch
			? e1.changedTouches[0].clientX
			: e1.clientX;
		dragBox.value.pos4 = e1IsTouch
			? e1.changedTouches[0].clientY
			: e1.clientY;

		const onMove = e => {
			const e2 = e || window.event;
			const e2IsTouch = e2.type === "touchmove";
			if (!e2IsTouch) e2.preventDefault();

			// Get the clientX and clientY
			const e2ClientX = e2IsTouch
				? e2.changedTouches[0].clientX
				: e2.clientX;
			const e2ClientY = e2IsTouch
				? e2.changedTouches[0].clientY
				: e2.clientY;

			// calculate the new cursor position:
			dragBox.value.pos1 = dragBox.value.pos3 - e2ClientX;
			dragBox.value.pos2 = dragBox.value.pos4 - e2ClientY;
			dragBox.value.pos3 = e2ClientX;
			dragBox.value.pos4 = e2ClientY;
			// set the element's new position:
			dragBox.value.top -= dragBox.value.pos2;
			dragBox.value.left -= dragBox.value.pos1;

			if (
				dragBox.value.top >
				document.body.clientHeight - dragBox.value.height
			)
				dragBox.value.top =
					document.body.clientHeight - dragBox.value.height;
			if (dragBox.value.top < 0) dragBox.value.top = 0;
			if (
				dragBox.value.left >
				document.body.clientWidth - dragBox.value.width
			)
				dragBox.value.left =
					document.body.clientWidth - dragBox.value.width;
			if (dragBox.value.left < 0) dragBox.value.left = 0;
		};
		document.onmousemove = onMove;
		document.ontouchmove = onMove;

		const onUp = () => {
			document.onmouseup = null;
			document.ontouchend = null;
			document.onmousemove = null;
			document.ontouchmove = null;

			if (typeof onDragBoxUpdate.value === "function")
				onDragBoxUpdate.value();
		};
		document.onmouseup = onUp;
		document.ontouchend = onUp;
	};

	const onWindowResizeDragBox = () => {
		if (dragBox.value.debounceTimeout)
			clearTimeout(dragBox.value.debounceTimeout);

		dragBox.value.debounceTimeout = setTimeout(() => {
			if (
				dragBox.value.top === dragBox.value.latest.top &&
				dragBox.value.left === dragBox.value.latest.left
			) {
				resetBoxPosition();
			} else {
				if (
					dragBox.value.top >
					document.body.clientHeight - dragBox.value.height
				)
					dragBox.value.top =
						document.body.clientHeight - dragBox.value.height;
				if (dragBox.value.top < 0) dragBox.value.top = 0;
				if (
					dragBox.value.left >
					document.body.clientWidth - dragBox.value.width
				)
					dragBox.value.left =
						document.body.clientWidth - dragBox.value.width;
				if (dragBox.value.left < 0) dragBox.value.left = 0;

				if (typeof onDragBoxUpdate.value === "function")
					onDragBoxUpdate.value();
			}
		}, 50);
	};

	onMounted(async () => {
		resetBoxPosition(true);

		await nextTick();

		onWindowResizeDragBox();
		window.addEventListener("resize", onWindowResizeDragBox);
	});

	onUnmounted(() => {
		window.removeEventListener("resize", onWindowResizeDragBox);
		if (dragBox.value.debounceTimeout)
			clearTimeout(dragBox.value.debounceTimeout);
	});

	return {
		dragBox,
		setInitialBox,
		onDragBox,
		resetBoxPosition,
		onWindowResizeDragBox,
		setOnDragBoxUpdate
	};
};
