let paused = false;
let workers = [];
let totalTime = 0;
let totalAttempts = 0;
let names = [];

fetch("names.json").then(res => res.json()).then(json => names = json);

function showStats() {
	document.getElementById("attempts").innerText = totalAttempts;
	document.getElementById("speed").innerText = (totalAttempts / totalTime).toFixed(2); // TODO fix totalTime
}

function log(text, workerId) {
	const time = new Date().toLocaleTimeString("en-GB");

	let html = `<time>${time}</time> `;
	if (workerId) html += `<span class="worker-id">[${workerId}]</span> `;
	html += `${text}<br>`;

	document.getElementById("log").innerHTML += html;
	document.getElementById("log").scrollTo(0, document.getElementById("log").scrollHeight);
}

function resetWorkers() {
	log("Terminating workers");

	for (const worker of workers) {
		worker.postMessage({ type: "terminate" });
	}

	totalTime = 0;
	totalAttempts = 0;
}

function runWorkers() {
	const numbers = [].map.call(document.getElementsByClassName("number-input"), input => input.valueAsNumber)
		.filter(value => !isNaN(value));
	const winType = document.querySelector("input[name=win-type]:checked").value;

	resetWorkers();

	const amount = document.getElementById("workers").valueAsNumber;
	const batchSize = document.getElementById("batch-size").valueAsNumber;

	log(`Creating ${amount} workers`);
	log(`* Win type: ${winType}`);
	log(`* Numbers: ${numbers.join(", ")}`);

	const usedNames = [];

	for (let i = 0; i < amount; i++) {
		let name;
		do
			name = names[Math.floor(Math.random() * names.length)];
		while (usedNames.includes(name));
		usedNames.push(name);

		const worker = new Worker("worker.js");
		worker.addEventListener("message", message => {
			switch (message.data.type) {
				case "ready":
					if (!paused) worker.postMessage({ type: "run" });
					break;
				case "stats":
					totalTime += message.data.time;
					totalAttempts += message.data.attempts;

					showStats();
					break;
				case "log":
					log(message.data.text, message.data.id);
					break;
				case "terminate":
					worker.terminate();
					workers.splice(workers.indexOf(worker), 1);
					break;
			}
		});

		worker.postMessage({ type: "init", id: i + 1, numbers, winType, name, batchSize });
		workers.push(worker);
	}
}

document.getElementById("numbers-container").addEventListener("keydown", event => {
	// Add new input field on enter
	if (event.key === "Enter") {
		const input = document.createElement("input");
		input.type = "number";
		input.className = "number-input";
		input.min = 1;
		input.max = 90;

		event.target.parentElement.appendChild(input);
		input.focus();

		return;
	}

	// Remove empty input field on backspace
	if (event.key === "Backspace" || event.key === "Delete") {
		if (event.target.value !== "" || document.querySelectorAll("#numbers-container input").length < 2)
			return;

		if (event.target.previousElementSibling.localName === "input")
			event.target.previousElementSibling.focus();
		else
			event.target.nextElementSibling.focus();

		event.target.parentElement.removeChild(event.target);

		event.preventDefault();
		return;
	}

	// Move between inputs on arrow up/down
	if (event.key === "ArrowUp" || event.key === "ArrowDown") {
		event.preventDefault();

		const elem = event.key === "ArrowUp"
			? event.target.previousElementSibling
			: event.target.nextElementSibling;

		if (!elem || elem.localName !== "input") return;

		elem.focus();
		return;
	}

	// Disallow non-digits
	const allowed = [/^Digit/, /^Arrow/, /Tab/];
	if (!event.altKey && !event.ctrlKey && !allowed.some(regex => regex.test(event.code))) {
		event.preventDefault();
	}
});

document.getElementById("pause").addEventListener("click", event => {
	paused = !paused;

	for (const worker of workers) {
		worker.postMessage({ type: paused ? "stop" : "run" });
	}

	event.target.innerText = paused ? "Start" : "Pause";
});

document.getElementById("workers").value = navigator.hardwareConcurrency ?? 1;

for (const container of document.getElementsByClassName("input-container")) {
	container.addEventListener("change", runWorkers);
}