function toggleSettings() {
	const panel = document.getElementById("settings-panel");
	panel.style.display = panel.style.display === "block"
		? "none"
		: "block";
	if (panel.style.display === "block") {
		const username = document.getElementById("username");
		username.focus();
		username.selectionStart = username.selectionEnd = username.value
			.length;
	}
}

function toggleUsers() {
	const panel = document.getElementById("users-panel");
	panel.style.display = panel.style.display === "block"
		? "none"
		: "block";
}

function toggleTheme() {
	const currentTheme = document.documentElement.getAttribute(
		"data-theme",
	);
	const newTheme = currentTheme === "dark" ? "light" : "dark";
	document.documentElement.setAttribute("data-theme", newTheme);
	localStorage.setItem("theme", newTheme);
}

async function deleteMessage(messageId) {
	if (confirm("Delete this message?")) {
		try {
			const response = await fetch("/messages", {
				method: "DELETE",
				headers: {
					"Content-Type": "application/json",
				},
				body: JSON.stringify({ messageId: messageId }),
			});

			if (response.ok) {
				updateMessagesInPlace();
			} else {
				console.error("Failed to delete message");
			}
		} catch (error) {
			console.error("Error deleting message:", error);
		}
	}
}

async function updateMessagesInPlace() {
	lastMessageCount = await getMessageCount();
	const currentScrollLocation = getScrollLocation();
	loadMessages(true, currentScrollLocation);
}

function getScrollLocation() {
	const messagesDiv = document.getElementById("messages");
	return messagesDiv.scrollTop;
}

function setScrollLocation(height) {
	const messagesDiv = document.getElementById("messages");
	messagesDiv.scrollTop = height;
}

document.addEventListener("click", function (event) {
	const settingsPanel = document.getElementById("settings-panel");
	const settingsButton = document.querySelector(".settings-button");
	const usersPanel = document.getElementById("users-panel");
	const usersButton = document.querySelector(".users-button");

	if (
		!settingsPanel.contains(event.target) &&
		!settingsButton.contains(event.target)
	) {
		settingsPanel.style.display = "none";
	}

	if (
		!usersPanel.contains(event.target) &&
		!usersButton.contains(event.target)
	) {
		usersPanel.style.display = "none";
	}
});

document.addEventListener("keypress", function (event) {
	if (event.key === "Enter" && !event.shiftKey) {
		const settingsPanel = document.getElementById("settings-panel");
		const inputPanel = document.getElementById("message");
		if (settingsPanel.contains(event.target)) {
			setUsername();
		}
		if (inputPanel.contains(event.target)) {
			event.preventDefault();
			sendMessage();
		}
	}
});

document.addEventListener("input", function (_) {
	const msg = document.getElementById("message");
	msg.style.height = "auto";
	msg.style.height = (msg.scrollHeight) + "px";
});

document.addEventListener("blur", function (_) {
	const msg = document.getElementById("message");
	msg.style.height = "auto";
}, true);

async function loadUsers() {
	try {
		const response = await fetch("/users");
		const data = await response.json();

		const usersList = document.getElementById("users-list");
		usersList.innerHTML = "";

		data.users.sort().forEach((user) => {
			const userDiv = document.createElement("div");
			userDiv.className = "user-item";
			userDiv.textContent = user;
			usersList.appendChild(userDiv);
		});
	} catch (error) {
		console.error("Error loading users:", error);
	}
}

async function getMessageCount() {
	try {
		const response = await fetch("/messages/length");
		const text = await response.json();
		return text.length;
	} catch (error) {
		console.error("Error getting message count:", error);
	}
}

let lastMessageCount = 0;
async function loadMessages(forceUpdate = false, scrollLocation) {
	try {
		const newMessageCount = await getMessageCount();

		const update = newMessageCount != lastMessageCount ||
			lastMessageCount === 0 || forceUpdate;

		let messagesDiv = document.getElementById("messages");
		while (messagesDiv === null) {
			await new Promise((resolve) =>
				setTimeout(resolve, 100)
			);
			messagesDiv = document.getElementById(
				"messages",
			);
		}
		if (messagesDiv.scrollTop != bottom) {
			// show a button to scroll to the bottom
			const scrollToBottomButton = document
				.getElementById(
					"scroll",
				);
			scrollToBottomButton.style.display = "block";
			scrollToBottomButton.onclick = scrollToBottom;
		} else {
			// hide the button
			const scrollToBottomButton = document
				.getElementById(
					"scroll",
				);
			scrollToBottomButton.style.display = "none";
		}
		if (update) {
			const response = await fetch("/messages");
			const text = await response.text();
			const tempDiv = document.createElement("div");
			tempDiv.innerHTML = text;

			const messages = tempDiv.getElementsByTagName("p");
			messagesDiv.innerHTML = "";
			Array.from(messages).forEach((msg) => {
				const messageDiv = document.createElement(
					"div",
				);
				messageDiv.className = "message";
				const [
					messageId,
					username,
					timestamp,
					content,
				] = msg
					.innerHTML.split(
						"<br>",
					);

				const usernameDiv = document.createElement(
					"div",
				);
				usernameDiv.innerHTML = username;
				compareUsername = usernameDiv.textContent;
				let deleteHtml = "";

				const embeddedContent = contentEmbedding(
					content,
				);

				if (
					compareUsername ===
						document.getElementById(
							"current-user",
						).textContent
				) {
					deleteHtml =
						`<button class="delete-button" title="Delete message" onclick="deleteMessage('${messageId}')" style="display: inline;">🗑️</button>`;
				}
				messageDiv.innerHTML = `
					<div class="message-header">
						<div class="username">${username} ${timestamp} ${deleteHtml}</div>
					</div>
					<div class="content">${embeddedContent}</div>`;

				messagesDiv.appendChild(messageDiv);
			});
			if (scrollLocation !== undefined) {
				setScrollLocation(scrollLocation);
			} else {
				scrollToBottom();
			}
			lastMessageCount = newMessageCount;
		}
	} catch (error) {
		console.error("Error loading messages:", error);
	}
}

function contentEmbedding(content) {
	return content.replace(
		/(?![^<]*>)(https?:\/\/[^\s<]+)/g,
		function (url) {
			const videoId = getYouTubeID(
				url,
			);
			if (videoId) {
				return `<div class="video-embed"><iframe 
									width="100%" 
									height="315" 
									src="https://www.youtube.com/embed/${videoId}" 
									frameborder="0" 
									onerror="console.log('Video failed to load:', this.src); this.style.display='none'"
									onload="console.log('Video loaded successfully:', this.src)" 
									allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" 
									allowfullscreen></iframe></div>`;
			} else if (isImageUrl(url)) {
				return `<div class="image-embed"><img 
									src="${url}" 
									alt="Embedded image" 
									loading="lazy" 
									onerror="console.log('Image failed to load:', this.src); this.style.display='none'"
									onload="console.log('Image loaded successfully:', this.src)"></div>`;
			}
			return `<a href="${url}" target="_blank" rel="noopener noreferrer">${url}</a>`;
		},
	);
}

function isImageUrl(url) {
	return url.match(/\.(jpeg|jpg|gif|png|webp|bmp)($|\?)/i) != null;
}

function getYouTubeID(url) {
	// First check if it's a Shorts URL
	if (url.includes("/shorts/")) {
		const shortsMatch = url.match(/\/shorts\/([^/?]+)/);
		return shortsMatch ? shortsMatch[1] : false;
	}

	// Otherwise check regular YouTube URLs
	const regExp =
		/^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#&?]*).*/;
	const match = url.match(regExp);
	return (match && match[7].length == 11) ? match[7] : false;
}

function scrollToBottom() {
	const messagesDiv = document.getElementById("messages");
	messagesDiv.scrollTop = messagesDiv.scrollHeight;
	bottom = messagesDiv.scrollTop;
}

async function checkUsername() {
	try {
		const response = await fetch("/username/status");
		const data = await response.json();
		if (!data.hasUsername) {
			document.getElementById("settings-panel").style
				.display = "block";
			const username = document.getElementById("username");
			username.focus();
			username.selectionStart =
				username.selectionEnd =
					username.value.length;
		}
	} catch (error) {
		console.error("Error checking username status:", error);
	}
}

async function updateCurrentUser() {
	try {
		const response = await fetch("/username/status");
		const data = await response.json();
		const userDiv = document.getElementById("current-user");
		if (data.hasUsername) {
			userDiv.textContent = data.username;
		} else {
			userDiv.textContent = "";
		}
	} catch (error) {
		console.error("Error getting username:", error);
	}
}

async function setUsername() {
	const username = document.getElementById("username").value;
	if (!username) {
		showUsernameStatus("Please enter a username", "red");
		return;
	}

	try {
		const response = await fetch("/username", {
			method: "PUT",
			headers: {
				"Content-Type": "application/json",
			},
			body: JSON.stringify({ username: username }),
		});

		const data = await response.json();

		if (response.ok) {
			showUsernameStatus(
				"Username set successfully!",
				"green",
			);
			updateCurrentUser();
			setTimeout(() => {
				document.getElementById("settings-panel").style
					.display = "none";
			}, 750);
			updateMessagesInPlace();
		} else {
			showUsernameStatus(
				data.error || "Failed to set username",
				"red",
			);
		}
	} catch (error) {
		showUsernameStatus("Error connecting to server", "red");
	}
}

let lastMessage = "";
async function sendMessage() {
	const messageInput = document.getElementById("message");
	const message = messageInput.value;
	if (!message) {
		return;
	}

	try {
		lastMessage = message;
		const response = await fetch("/messages", {
			method: "PUT",
			headers: {
				"Content-Type": "application/json",
			},
			body: JSON.stringify({ message: message }),
		});

		const data = await response.json();

		if (response.ok) {
			messageInput.value = "";
			messageInput.style.height = "auto";
			loadMessages(true);
		} else {
			showStatus(
				data.error || "Failed to send message",
				"red",
			);
		}
	} catch (error) {
		showStatus("Error connecting to server", "red");
	}
}

function showStatus(message, color) {
	const status = document.getElementById("status");
	status.textContent = message;
	status.style.color = color;
	setTimeout(() => {
		status.textContent = "";
	}, 3000);
}

function showUsernameStatus(message, color) {
	const status = document.getElementById("username-status");
	status.textContent = message;
	status.style.color = color;
	setTimeout(() => {
		status.textContent = "";
	}, 3000);
}

async function pingCheck() {
	try {
		await fetch("/ping", { method: "POST" });
	} catch (error) {
		console.error("Ping failed:", error);
	}
}

async function timeZoneCheck() {
	try {
		const timeZone =
			Intl.DateTimeFormat().resolvedOptions().timeZone;
		const response = await fetch("/timezone", {
			method: "POST",
			headers: {
				"Content-Type": "application/json",
			},
			body: JSON.stringify({ timezone: timeZone }),
		});
		const data = await response.json();
		if (!response.ok) {
			console.error("Failed to set timezone:", data.error);
		}
	} catch (error) {
		console.error("Error checking timezone:", error);
	}
}

function initializeTheme() {
	const savedTheme = localStorage.getItem("theme");
	if (savedTheme) {
		document.documentElement.setAttribute("data-theme", savedTheme);
	} else {
		// Check system preference
		if (
			window.matchMedia &&
			window.matchMedia("(prefers-color-scheme: light)")
				.matches
		) {
			document.documentElement.setAttribute(
				"data-theme",
				"light",
			);
		} else {
			document.documentElement.setAttribute(
				"data-theme",
				"dark",
			);
		}
	}
}

document.addEventListener("keyup", function (event) {
	const inputPanel = document.getElementById("message");
	if (inputPanel.contains(event.target) && event.key === "ArrowUp") {
		if (inputPanel.value === "") {
			inputPanel.value = lastMessage;
		}
	}
});

let bottom = 0;
async function initialize() {
	usersPanel = document.getElementById("users-panel");
	if (usersPanel) {
		usersPanel.style.display = "none";
	}
	settingsPanel = document.getElementById("settings-panel");
	if (settingsPanel) {
		settingsPanel.style.display = "none";
	}
	initializeTheme();
	await checkUsername();
	await updateCurrentUser();
	await timeZoneCheck();
	setInterval(loadMessages, 1000);
	setInterval(loadUsers, 1000);
	setInterval(pingCheck, 3000);
	await loadMessages(true);
	initializeSearchBox();
}

function initializeSearchBox() {
	const searchContainer = document.getElementById("searchContainer");
	const searchButton = document.getElementById("searchButton");
	const searchInput = document.getElementById("searchInput");
	const searchCount = document.getElementById("searchCount");

	let currentMatchIndex = -1;
	let matches = [];

	function escapeRegExp(string) {
		return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
	}

	function clearHighlights() {
		// Remove all existing highlights
		const highlights = document.querySelectorAll(
			".search-highlight",
		);
		highlights.forEach((highlight) => {
			const parent = highlight.parentNode;
			parent.replaceChild(
				document.createTextNode(highlight.textContent),
				highlight,
			);
			parent.normalize();
		});
		matches = [];
		currentMatchIndex = -1;
		searchCount.textContent = "";
	}

	function findTextNodes(element, textNodes = []) {
		// Skip certain elements
		if (element.nodeType === Node.ELEMENT_NODE) { // Check if it's an element node first
			if (
				element.tagName === "SCRIPT" ||
				element.tagName === "STYLE" ||
				element.tagName === "NOSCRIPT" ||
				(element.classList &&
					element.classList.contains(
						"search-container",
					)) ||
				(element.classList &&
					element.classList.contains(
						"search-highlight",
					))
			) {
				return textNodes;
			}
		}

		// Check if this node is a text node with non-whitespace content
		if (
			element.nodeType === Node.TEXT_NODE &&
			element.textContent.trim()
		) {
			textNodes.push(element);
		}

		// Recursively check all child nodes
		const children = element.childNodes;
		for (let i = 0; i < children.length; i++) {
			findTextNodes(children[i], textNodes);
		}

		return textNodes;
	}

	function findAndHighlight(searchText) {
		if (!searchText) {
			clearHighlights();
			return;
		}

		clearHighlights();

		const searchRegex = new RegExp(escapeRegExp(searchText), "gi");
		const textNodes = findTextNodes(document.body);

		textNodes.forEach((node) => {
			const matches = [
				...node.textContent.matchAll(searchRegex),
			];
			if (matches.length > 0) {
				const span = document.createElement("span");
				span.innerHTML = node.textContent.replace(
					searchRegex,
					(match) =>
						`<span class="search-highlight">${match}</span>`,
				);
				node.parentNode.replaceChild(span, node);
			}
		});

		// Collect all highlights
		matches = Array.from(
			document.querySelectorAll(".search-highlight"),
		);
		if (matches.length > 0) {
			currentMatchIndex = 0;
			matches[0].classList.add("current");
			matches[0].scrollIntoView({
				behavior: "smooth",
				block: "center",
			});
		}

		// Update count
		searchCount.textContent = matches.length > 0
			? `${currentMatchIndex + 1}/${matches.length}`
			: "No matches";
	}

	function nextMatch() {
		if (matches.length === 0) return;

		matches[currentMatchIndex].classList.remove("current");
		currentMatchIndex = (currentMatchIndex + 1) % matches.length;
		matches[currentMatchIndex].classList.add("current");
		matches[currentMatchIndex].scrollIntoView({
			behavior: "smooth",
			block: "center",
		});
		searchCount.textContent = `${
			currentMatchIndex + 1
		}/${matches.length}`;
	}

	searchButton.addEventListener("click", () => {
		if (!searchContainer.classList.contains("expanded")) {
			searchContainer.classList.add("expanded");
			searchInput.focus();
		} else {
			nextMatch();
		}
	});

	searchInput.addEventListener("input", (e) => {
		findAndHighlight(e.target.value.trim());
	});

	searchInput.addEventListener("keydown", (e) => {
		if (e.key === "Enter") {
			nextMatch();
		} else if (e.key === "Escape") {
			searchContainer.classList.remove("expanded");
			searchInput.value = "";
			clearHighlights();
		}
	});

	// Debug function to check search coverage (call from console: checkSearchCoverage())
	window.checkSearchCoverage = function () {
		const textNodes = findTextNodes(document.body);
		console.log(
			"Total searchable text nodes found:",
			textNodes.length,
		);
		textNodes.forEach((node, i) => {
			console.log(`Node ${i + 1}:`, {
				text: node.textContent,
				parent: node.parentElement.tagName,
				path: getNodePath(node),
			});
		});
	};

	function getNodePath(node) {
		const path = [];
		while (node && node.parentElement) {
			let index = Array.from(node.parentElement.childNodes)
				.indexOf(node);
			path.unshift(`${node.parentElement.tagName}[${index}]`);
			node = node.parentElement;
		}
		return path.join(" > ");
	}

	// Close search when clicking outside
	document.addEventListener("click", (e) => {
		if (!searchContainer.contains(e.target)) {
			searchContainer.classList.remove("expanded");
			searchInput.value = "";
			clearHighlights();
		}
	});
}

initialize();