let viewingTemplate = null;
let googleUser = null;
let templateData = [];

function googleOnSignIn(googleUserData) {
	googleUser = googleUserData;
	const signInElem = document.getElementById("google-auth-sign-in");
	const signOutElem = document.getElementById("google-auth-sign-out");
	signInElem.classList.add("hidden");
	signOutElem.classList.remove("hidden");
}

async function googleSignOut() {
	if (googleUser) {
		googleUser = null;
		await gapi.auth2.getAuthInstance().signOut();
		const signInElem = document.getElementById("google-auth-sign-in");
		const signOutElem = document.getElementById("google-auth-sign-out");
		signInElem.classList.remove("hidden");
		signOutElem.classList.add("hidden");
	}
}

window.addEventListener("DOMContentLoaded", async (event) => {
	document.getElementById("template-new-form").addEventListener("submit", async (event) => {
		event.preventDefault();

		const errorListContainer = document.getElementById("template-new-errors");
		errorListContainer.innerHTML = "";

		const form = document.getElementById("template-new-form");
		const formData = new FormData(form);

		const name = formData.get("name");

		const imageFile = formData.get("image");
		const fileReader = new FileReader();
		const fileReaderCompletePromise = new Promise((resolve, reject) => {
			fileReader.addEventListener("loadend", (event) => resolve());
		});
		fileReader.readAsDataURL(imageFile);

		const description = formData.get("description");
		const attribution = formData.get("attribution");

		const cropXStart = parseInt(formData.get("cropxstart"), 10);
		const cropYStart = parseInt(formData.get("cropystart"), 10);
		const cropXEnd = parseInt(formData.get("cropxend"), 10);
		const cropYEnd = parseInt(formData.get("cropyend"), 10);

		const locXStart = parseInt(formData.get("locxstart"), 10);
		const locYStart = parseInt(formData.get("locystart"), 10);
		const locXEnd = parseInt(formData.get("locxend"), 10);
		const locYEnd = parseInt(formData.get("locyend"), 10);

		if (
			isNaN(cropXStart) ||
			isNaN(cropYStart) ||
			isNaN(cropXEnd) ||
			isNaN(cropYEnd) ||
			isNaN(locXStart) ||
			isNaN(locYStart) ||
			isNaN(locXEnd) ||
			isNaN(locYEnd)
		) {
			const parseNumbersError = document.createElement("li");
			parseNumbersError.innerText = "All crop and location information must be entered";
			errorListContainer.appendChild(parseNumbersError);
		}

		await fileReaderCompletePromise;

		const imageDataURL = fileReader.result;
		if (!imageDataURL.startsWith("data:image/png;base64,")) {
			const imageReadError = document.createElement("li");
			imageReadError.innerText = "Couldn't read the image data, or the image wasn't a valid PNG";
			errorListContainer.appendChild(imageReadError);
			return;
		}
		const image = imageDataURL.substring(22);

		const submitData = {
			name: name,
			image: image,
			description: description,
			attribution: attribution,
			crop: [cropXStart, cropYStart, cropXEnd, cropYEnd],
			location: [locXStart, locYStart, locXEnd, locYEnd],
		};
		if (googleUser) {
			submitData.token = googleUser.getAuthResponse().id_token;
		}

		if (!errorListContainer.hasChildNodes()) {
			const submitResponse = await fetch("/thrimshim/add-template", {
				method: "POST",
				body: JSON.stringify(submitData),
				headers: { "Content-Type": "application/json" },
			});
			if (!submitResponse.ok) {
				const submitError = document.createElement("li");
				submitError.innerText = await submitResponse.text();
				errorListContainer.appendChild(submitError);
				return;
			}

			addTemplate(templateData.length, submitData);
			templateData.push(submitData);

			form.reset();
		}
	});

	document.getElementById("google-auth-sign-out").addEventListener("click", (_event) => {
		googleSignOut();
	});

	const templateDataResponse = await fetch("/thrimshim/templates");
	if (!templateDataResponse.ok) {
		return;
	}
	templateData = await templateDataResponse.json();

	for (const [index, template] of templateData.entries()) {
		addTemplate(index, template);
	}
});

function generateTemplateDOM(index, template) {
	const { name, description, attribution, crop, location } = template;

	const editForm = document.createElement("form");
	editForm.id = `template-data-edit-form-${index}`;

	const nameCell = document.createElement("td");
	const nameReadCell = document.createElement("div");
	nameReadCell.classList.add("template-data-view");
	nameReadCell.innerText = name;
	const nameEditCell = document.createElement("div");
	nameEditCell.classList.add("template-data-edit", "hidden");
	const nameEditField = document.createElement("input");
	nameEditField.type = "text";
	nameEditField.name = "name";
	nameEditField.value = name;
	nameEditField.form = editForm.id;
	nameEditCell.appendChild(nameEditField);
	nameCell.appendChild(nameReadCell);
	nameCell.appendChild(nameEditCell);

	const descriptionCell = document.createElement("td");
	const descriptionReadCell = document.createElement("div");
	descriptionReadCell.classList.add("template-data-view");
	descriptionReadCell.innerText = description;
	const descriptionEditCell = document.createElement("div");
	descriptionEditCell.classList.add("template-data-edit", "hidden");
	const descriptionEditField = document.createElement("textarea");
	descriptionEditField.name = "description";
	descriptionEditField.value = description;
	descriptionEditField.form = editForm.id;
	descriptionEditCell.appendChild(descriptionEditField);
	descriptionCell.appendChild(descriptionReadCell);
	descriptionCell.appendChild(descriptionEditCell);

	const attributionCell = document.createElement("td");
	const attributionReadCell = document.createElement("div");
	attributionReadCell.classList.add("template-data-view");
	attributionReadCell.innerText = attribution;
	const attributionEditCell = document.createElement("div");
	attributionEditCell.classList.add("template-data-edit", "hidden");
	const attributionEditField = document.createElement("input");
	attributionEditField.type = "text";
	attributionEditField.name = "attribution";
	attributionEditField.value = attribution;
	attributionEditField.form = editForm.id;
	attributionEditCell.appendChild(attributionEditField);
	attributionCell.appendChild(attributionReadCell);
	attributionCell.appendChild(attributionEditCell);

	const cropCell = document.createElement("td");
	const cropReadCell = document.createElement("div");
	cropReadCell.classList.add("template-data-view");
	cropReadCell.innerText = `(${crop[0]}, ${crop[1]}) to (${crop[2]}, ${crop[3]})`;
	const cropEditCell = document.createElement("div");
	cropEditCell.classList.add("template-data-edit", "hidden");

	const cropXStartField = document.createElement("input");
	cropXStartField.name = "cropxstart";
	setCoordNumberFieldProps(cropXStartField, "X");
	cropXStartField.value = crop[0];
	cropXStartField.form = editForm.id;
	const cropYStartField = document.createElement("input");
	cropYStartField.name = "cropystart";
	setCoordNumberFieldProps(cropYStartField, "Y");
	cropYStartField.value = crop[1];
	cropYStartField.form = editForm.id;
	const cropXEndField = document.createElement("input");
	cropXEndField.name = "cropxend";
	setCoordNumberFieldProps(cropXEndField, "X");
	cropXEndField.value = crop[2];
	cropXEndField.form = editForm.id;
	const cropYEndField = document.createElement("input");
	cropYEndField.name = "cropyend";
	setCoordNumberFieldProps(cropYEndField, "Y");
	cropYEndField.value = crop[3];
	cropYEndField.form = editForm.id;

	cropEditCell.appendChild(document.createTextNode("("));
	cropEditCell.appendChild(cropXStartField);
	cropEditCell.appendChild(document.createTextNode(", "));
	cropEditCell.appendChild(cropYStartField);
	cropEditCell.appendChild(document.createTextNode(") to ("));
	cropEditCell.appendChild(cropXEndField);
	cropEditCell.appendChild(document.createTextNode(", "));
	cropEditCell.appendChild(cropYEndField);
	cropEditCell.appendChild(document.createTextNode(")"));

	cropCell.appendChild(cropReadCell);
	cropCell.appendChild(cropEditCell);

	const locationCell = document.createElement("td");
	const locationReadCell = document.createElement("div");
	locationReadCell.classList.add("template-data-view");
	locationReadCell.innerText = `(${location[0]}, ${location[1]}) to (${location[2]}, ${location[3]})`;
	const locationEditCell = document.createElement("div");
	locationEditCell.classList.add("template-data-edit", "hidden");

	const locationXStartField = document.createElement("input");
	locationXStartField.name = "locxstart";
	setCoordNumberFieldProps(locationXStartField, "X");
	locationXStartField.value = location[0];
	locationXStartField.form = editForm.id;
	const locationYStartField = document.createElement("input");
	locationYStartField.name = "locystart";
	setCoordNumberFieldProps(locationYStartField, "Y");
	locationYStartField.value = location[1];
	locationYStartField.form = editForm.id;
	const locationXEndField = document.createElement("input");
	locationXEndField.name = "locxend";
	setCoordNumberFieldProps(locationXEndField, "X");
	locationXEndField.value = location[2];
	locationXEndField.form = editForm.id;
	const locationYEndField = document.createElement("input");
	locationYEndField.name = "locyend";
	setCoordNumberFieldProps(locationYEndField, "Y");
	locationYEndField.value = location[3];
	locationYEndField.form = editForm.id;

	locationEditCell.appendChild(document.createTextNode("("));
	locationEditCell.appendChild(locationXStartField);
	locationEditCell.appendChild(document.createTextNode(", "));
	locationEditCell.appendChild(locationYStartField);
	locationEditCell.appendChild(document.createTextNode(") to ("));
	locationEditCell.appendChild(locationXEndField);
	locationEditCell.appendChild(document.createTextNode(", "));
	locationEditCell.appendChild(locationYEndField);
	locationEditCell.appendChild(document.createTextNode(")"));

	locationCell.appendChild(locationReadCell);
	locationCell.appendChild(locationEditCell);

	const previewCell = document.createElement("td");
	const previewReadCell = document.createElement("div");
	previewReadCell.id = `template-list-preview-${index}`;
	previewReadCell.classList.add("template-data-view");
	const previewLink = document.createElement("a");
	previewLink.href = `javascript:showPreview(${index})`;
	previewLink.innerText = "Preview";
	previewReadCell.appendChild(previewLink);
	const previewEditCell = document.createElement("div");
	previewEditCell.classList.add("template-data-edit", "hidden");
	const imageEditField = document.createElement("input");
	imageEditField.name = "image";
	imageEditField.type = "file";
	imageEditField.accept = "image/png";
	imageEditField.form = editForm.id;
	previewEditCell.appendChild(imageEditField);
	previewCell.appendChild(previewReadCell);
	previewCell.appendChild(previewEditCell);

	const editCell = document.createElement("td");
	const editReadCell = document.createElement("div");
	editReadCell.classList.add("template-data-view");
	const switchToEditButton = document.createElement("button");
	switchToEditButton.type = "button";
	switchToEditButton.innerText = "Edit";
	editReadCell.appendChild(switchToEditButton);
	const editEditCell = document.createElement("div");
	editEditCell.classList.add("template-data-edit", "hidden");
	const editSubmitButton = document.createElement("button");
	editSubmitButton.type = "submit";
	editSubmitButton.innerText = "Submit";
	const editErrors = document.createElement("ul");
	editErrors.id = `template-data-edit-errors-${index}`;
	editErrors.classList.add("template-data-edit-errors");
	editForm.appendChild(editSubmitButton);
	editForm.appendChild(editErrors);
	editEditCell.appendChild(editForm);
	editCell.appendChild(editReadCell);
	editCell.appendChild(editEditCell);

	const templateRow = document.createElement("tr");
	templateRow.id = `template-list-data-${index}`;
	templateRow.appendChild(nameCell);
	templateRow.appendChild(descriptionCell);
	templateRow.appendChild(attributionCell);
	templateRow.appendChild(cropCell);
	templateRow.appendChild(locationCell);
	templateRow.appendChild(previewCell);
	templateRow.appendChild(editCell);

	switchToEditButton.addEventListener("click", (event) => {
		for (const element of templateRow.getElementsByClassName("template-data-view")) {
			element.classList.add("hidden");
		}
		for (const element of templateRow.getElementsByClassName("template-data-edit")) {
			element.classList.remove("hidden");
		}
	});

	templateRow.addEventListener("submit", async (event) => {
		event.preventDefault();

		editErrors.innerHTML = "";

		const name = nameEditField.value;

		const description = descriptionEditField.value;
		const attribution = attributionEditField.value;

		const cropXStart = parseInt(cropXStartField.value, 10);
		const cropYStart = parseInt(cropYStartField.value, 10);
		const cropXEnd = parseInt(cropXEndField.value, 10);
		const cropYEnd = parseInt(cropYEndField.value, 10);
		const locXStart = parseInt(locationXStartField.value, 10);
		const locYStart = parseInt(locationYStartField.value, 10);
		const locXEnd = parseInt(locationXEndField.value, 10);
		const locYEnd = parseInt(locationYEndField.value, 10);

		if (
			isNaN(cropXStart) ||
			isNaN(cropYStart) ||
			isNaN(cropXEnd) ||
			isNaN(cropYEnd) ||
			isNaN(locXStart) ||
			isNaN(locXEnd) ||
			isNaN(locYStart) ||
			isNaN(locYEnd)
		) {
			const parseNumbersError = document.createElement("li");
			parseNumbersError.innerText = "All crop and location information must be entered";
			editErrors.appendChild(parseNumbersError);
		}

		const submitData = {
			name: name,
			description: description,
			attribution: attribution,
			crop: [cropXStart, cropYStart, cropXEnd, cropYEnd],
			location: [locXStart, locYStart, locXEnd, locYEnd],
		};

		const imageFiles = imageEditField.files;
		if (imageFiles.length > 0) {
			const fileReader = new FileReader();
			const fileReaderCompletePromise = new Promise((resolve, reject) => {
				fileReader.addEventListener("loadend", (event) => resolve());
			});
			fileReader.readAsDataURL(imageFiles[0]);
			await fileReaderCompletePromise;

			const imageDataURL = fileReader.result;
			if (imageDataURL.startsWith("data:image/png;base64,")) {
				submitData.image = imageDataURL.substring(22);
			} else {
				const imageError = document.createElement("li");
				imageError.innerText = "Failed to process image as PNG";
				editErrors.appendChild(imageError);
			}
		}
		if (googleUser) {
			submitData.token = googleUser.getAuthResponse().id_token;
		}

		if (editErrors.hasChildNodes()) {
			return;
		}

		const origName = templateData[index].name;
		const encodedName = encodeURIComponent(origName);
		const submitResponse = await fetch(`/thrimshim/update-template/${encodedName}`, {
			method: "POST",
			body: JSON.stringify(submitData),
			headers: { "Content-Type": "application/json" },
		});
		if (!submitResponse.ok) {
			const submitError = document.createElement("li");
			submitError.innerText = await submitResponse.text();
			editErrors.appendChild(submitError);
			return;
		}

		templateData[index].name = name;
		if (submitData.hasOwnProperty("image")) {
			templateData[index].image = submitData.image;
		}
		templateData[index].description = description;
		templateData[index].attribution = attribution;
		templateData[index].crop = submitData.crop;
		templateData[index].location = submitData.location;

		const templateDOM = generateTemplateDOM(index, templateData[index]);
		templateRow.replaceWith(templateDOM);
	});

	return templateRow;
}

function addTemplate(index, template) {
	const templateDOM = generateTemplateDOM(index, template);
	document.getElementById("template-list-data").appendChild(templateDOM);
}

function setCoordNumberFieldProps(field, direction) {
	field.type = "number";
	field.placeholder = direction;
	field.min = 0;
	field.step = 1;
	field.classList.add("template-coord");
}

function showPreview(index) {
	const template = templateData[index];
	const previewCell = document.getElementById(`template-list-preview-${index}`);
	if (!previewCell) {
		return;
	}

	const previewContents = document.createElement("img");
	previewContents.classList.add("template-list-preview");
	previewContents.src = `/thrimshim/template/${template.name}.png`;

	previewCell.innerHTML = "";
	previewCell.appendChild(previewContents);
}