<div id="command-line" class="w-full flex flex-row bg-base">
	<input
		aria-hidden="true"
		id="command-line-input"
		type="text"
		class="bg-base focus:outline-none active:outline-none cursor-default caret-transparent m-0"
	/>
	<div id="caret" aria-hidden="true" class="bg-text inline-block">&nbsp;</div>
	<p
		aria-hidden="true"
		id="status-text"
		class="absolute w-full h-full bg-base hidden italic"
	>
	</p>
</div>

<script>
	const cmds: Record<string, () => void> = {
		q: () => {
			const cmdEvent = new CustomEvent("closebuffer");
			window.dispatchEvent(cmdEvent);
		},
		help: () => {
			const cmdEvent = new CustomEvent("openhelp");
			window.dispatchEvent(cmdEvent);
		},
		"help iccf": () => {
			const cmdEvent = new CustomEvent("openiccf");
			window.dispatchEvent(cmdEvent);
		},
	};

	const container = document.getElementById("command-line") as HTMLDivElement;
	const commandLineInput = document.getElementById(
		"command-line-input",
	) as HTMLInputElement;
	const caret = document.getElementById("caret") as HTMLDivElement;
	const statusText = document.getElementById(
		"status-text",
	) as HTMLParagraphElement;
	const allowedCharRegex = /[\w\d\s!@#$%^&*()-_+=|\\~`{[}\]:;"'<,>.?/]/;

	let isInCmdMode = false;

	commandLineInput.value = "";
	caret.style.display = "none";

	function enableCmdMode() {
		caret.style.display = "block";
		statusText.classList.add("hidden");
		commandLineInput.value = ":";
		commandLineInput.style.width = "1ch";
		isInCmdMode = true;

		const event = new Event("cmdmodeenabled");
		container.dispatchEvent(event);
	}

	function disableCmdMode({ clear } = { clear: true }) {
		caret.style.display = "none";
		isInCmdMode = false;
		if (clear) {
			commandLineInput.value = "";
			commandLineInput.style.width = "0ch";
		}

		const event = new Event("cmdmodedisabled");
		container.dispatchEvent(event);
	}

	function appendChar(event: KeyboardEvent) {
		commandLineInput.value += event.key;
		commandLineInput.style.width = `${commandLineInput.value.length}ch`;
	}

	function deleteChar() {
		commandLineInput.value = commandLineInput.value.substring(
			0,
			commandLineInput.value.length - 1,
		);
		commandLineInput.style.width = `${commandLineInput.value.length}ch`;
	}

	function executeCommand() {
		disableCmdMode({ clear: false });
		const command = commandLineInput.value.substring(1);
		const fn = cmds[command];
		if (fn) {
			fn();
		} else {
			statusText.innerHTML = `E492: Not an editor command: ${command}`;
			statusText.classList.remove("hidden");
			statusText.classList.add("text-red");
		}
	}

	document.addEventListener("keydown", (event) => {
		switch (event.key) {
			case ":":
				if (!isInCmdMode) {
					enableCmdMode();
				} else {
					appendChar(event);
				}
				break;

			case "Escape":
				if (isInCmdMode) {
					event.preventDefault();
					disableCmdMode();
				}
				break;

			case "Backspace":
				if (!isInCmdMode) break;
				if (commandLineInput.value === ":") {
					disableCmdMode();
				} else {
					deleteChar();
				}
				break;

			case "Enter":
				executeCommand();
				break;

			default:
				if (
					event.key.length === 1 &&
					allowedCharRegex.test(event.key) &&
					isInCmdMode
				) {
					appendChar(event);
				}
				break;
		}
	});
</script>
