"use strict";

const React = require("react");
const ReactDOM = require("react-dom");
const Promise = require("bluebird");
const documentReadyPromise = require("document-ready-promise");
const debounce = require("debounce");
const { expression } = require("dataprog");

const generateSelector = require("./generate-selector");
const useStateRef = require("./use-state-ref");
const useMemoizedPosition = require("./use-memoized-position");
const elementsFromPoint = require("./elements-from-point");
const uniqueElementId = require("./unique-element-id");

function Overlay() {
	let [ scrollX, setScrollX ] = React.useState();
	let [ scrollY, setScrollY ] = React.useState();
	let [ hoveredElement, setHoveredElement ] = React.useState();
	let [ isHovering, setIsHovering, isHoveringRef ] = useStateRef(true);
	let [ isPicking, setIsPicking, isPickingRef ] = useStateRef(false);
	let [ elementList, setElementList ] = React.useState([]);
	let [ selectedElement, setSelectedElement ] = React.useState();
	let [ pickHoveredElement, setPickHoveredElement ] = React.useState();
	let [ pickedElement, setPickedElement ] = React.useState();

	let enabledRef = React.useRef(true);

	React.useEffect(() => {
		window.addEventListener("scroll", debounce((event) => {
			setScrollX(window.scrollX);
			setScrollY(window.scrollY);
		}), 20);

		let allElements = document.querySelectorAll("*");

		for (let element of allElements) {
			/* TODO: Investigate whether switching to mousemove + elementFromPoint is more performant */
			element.addEventListener("mouseover", (event) => {
				event.stopPropagation();

				if (isHoveringRef.current) {
					setHoveredElement(element);
				}
			});

			function clickHandler(event) {
				if (enabledRef.current) {
					event.preventDefault();
					event.stopPropagation();

					if (isHoveringRef.current) {
						setIsHovering(false);
						setIsPicking(true);

						let candidateElements = elementsFromPoint(event.clientX, event.clientY);

						setElementList(candidateElements);
						setSelectedElement(candidateElements[0]);
					}
				}
			}

			element.addEventListener("click", clickHandler);
			element.addEventListener("mousedown", clickHandler);
			element.addEventListener("mouseup", clickHandler);
		}
	}, []);

	let hoveredPosition = useMemoizedPosition(hoveredElement, [ scrollX, scrollY ]);
	let selectedPosition = useMemoizedPosition(selectedElement, [ scrollX, scrollY ]);
	let pickedPosition = useMemoizedPosition(pickedElement, [ scrollX, scrollY ]);
	let pickHoveredPosition = useMemoizedPosition(pickHoveredElement, [ scrollX, scrollY ]);

	return (
		<div className="___scraping___tool___overlay active">
			{(hoveredPosition != null && isHovering)
				? <HoverHighlight element={hoveredElement} {... hoveredPosition} />
				: null
			}
			{(selectedPosition != null)
				? <PrimarySelectionHighlight element={selectedElement} {... selectedPosition} />
				: null
			}
			{(pickedPosition != null && isPicking)
				? <HoverHighlight element={pickedElement} {... pickedPosition} />
				: null
			}
			{(pickHoveredPosition != null && isPicking)
				? <HoverHighlight element={pickHoveredElement} {... pickHoveredPosition} />
				: null
			}
			{(isPicking)
				? <Picker candidates={elementList} onHover={setPickHoveredElement} />
				: null
			}
		</div>
	);
}

function Picker({ candidates, onHover }) {
	return (
		<div className="___scraping___tool___candidatePicker">
			{candidates.map((candidate) => {
				return <PickerCandidate
					key={uniqueElementId(candidate)}
					element={candidate}
					onEnter={() => onHover(candidate)}
					onLeave={() => onHover(null)}
				/>;
			})}
		</div>
	);
}

function PickerCandidate({ element, onEnter, onLeave }) {
	return (
		<div className="___scraping___tool___candidate" onMouseEnter={onEnter} onMouseLeave={onLeave}>
			{generateSelector(element)}
		</div>
	);
}

function HoverHighlight({ x, y, width, height, element }) {
	let boxStyle = { left: x, top: y, width: width, height: height };
	let tooltipStyle = { left: x, top: y + height };

	return (<>
		<div className="___scraping___tool___hover" style={boxStyle} />
		{(element != null)
			? <div className="___scraping___tool___tooltip" style={tooltipStyle}>{ generateSelector(element) }</div>
			: null
		}
	</>);
}

function PrimarySelectionHighlight({ x, y, width, height, element }) {
	let boxStyle = { left: x, top: y, width: width, height: height };

	return (<>
		<div className="___scraping___tool___selection" style={boxStyle} />
	</>);
}

Promise.try(() => {
	return documentReadyPromise();
}).then(() => {
	let $overlay = document.querySelector(".___scraping___tool___overlay");
	let $tool = document.querySelector(".___scraping___tool");

	ReactDOM.render(<Overlay />, $overlay);
});
