document.addEventListener("DOMContentLoaded", function(event) {
	formatDates();
	getPostTexts();
	getUserDetails();
	handleAvatarHover();
	initFileUpload();
	setupUploadPostPreview();
});

function formatDates() {
	let timestampElements = document.querySelectorAll('.postdate[ts]');
	timestampElements.forEach(function(el) {
		let d = new Date(el.attributes['ts'].value * 1000);
		el.innerText = d.toLocaleString();
	});
}

function getPostTexts() {
	let boxes = document.querySelectorAll('.post-box');
	// TODO: Implement multiple fetches with one call
	boxes.forEach(function(el) {
		let id = el.querySelector('.post-meta-box').querySelector('span').innerText.replace('#','');
		get('get_posttext.php?id='+id).then(function(response) {
			let info;
			try {
				info = JSON.parse(response);
			} catch (error) {
				showError(`Unknown response from server: ${response}`);
				return;
			}
			let postTextBox = el.querySelector('.post-text-box');
			let loader = postTextBox.querySelector('.loader');
			if (loader !== null) {
				postTextBox.removeChild(loader);
			}
			if (info.success) {
				postTextBox.innerHTML = info.text;
			} else {
				if (info.error == 404) {
					console.log('Post ', id, ' not found');
				} else {
					console.log('Error fetching post ', id, 'Error code: ', info.error);
				}
			}
		}, function(error) {
			console.log('Error fetching post ', id, error);
		});
	});
}

function getUserDetails() {
	let boxes = document.querySelectorAll('.user-box');
	// TODO: Implement multiple fetches with one call
	boxes.forEach(function(el) {
		let userBox = el.querySelector('.username');
		if (userBox == null) {
			userBox = el.querySelector('span');
		}
		let id = userBox.innerText;
		get('get_userdetails.php?id='+id).then(function(response) {
			let info;
			try {
				info = JSON.parse(response);
			} catch (error) {
				showError(`Unknown response from server: ${response}`);
				return;
			}
			let loader = userBox.querySelector('.loader-small');
			if (loader !== null) {
				userBox.removeChild(loader);
			}
			if (info.success) {
				if (info.name != null) {
					el.innerHTML = '<span>' + info.name + '</span><span class="username">' + id + '</span>';
				}
				let presenceIndicator = document.createElement('div');
				presenceIndicator.classList.add('presence-indicator');
				switch (info.presence) {
					case 0:
						presenceIndicator.style.borderColor = "red";
						presenceIndicator.style.setProperty('border-color', 'var(--red)');
						break;
					case 1:
						presenceIndicator.style.borderColor = "green";
						presenceIndicator.style.setProperty('border-color', 'var(--green)');
						break;
				}
				el.appendChild(presenceIndicator);
			} else {
				if (info.error == 404) {
					console.log('User ', id, ' not found');
				} else {
					console.log('Error fetching user ', id, 'Error code: ', info.error);
				}
			}
		}, function(error) {
			console.log('Error fetching user ', id, error);
		});

	});
}

function handleAvatarHover() {
	let avatars = document.querySelectorAll('img.avatar');
	avatars.forEach(function(el) {
		el.addEventListener('mouseenter', function() {
			// Blur non hovered
			let nonHovered = document.querySelectorAll('img.avatar:not(:hover)');
			nonHovered.forEach(function(img) {
				img.classList.add('blur');
				//img.classList.remove('unblur');
				//img.style.filter = "blur(5px)";
			});
		});
		el.addEventListener('mouseleave', function() {
			// Unblur
			let avtrs = document.querySelectorAll('img.avatar');
			avtrs.forEach(function(img) {
				img.classList.remove('blur');
				//img.classList.add('unblur');
				//img.style.filter = "blur(0px)";
			});
		});
	});
}

function showLoginForm(authUrl) {
	const authDiv = document.getElementById("authorizeDiv");
	authDiv.classList.remove("hidden");
	authDiv.querySelector("a").href = authUrl;
}

function initUploadForm(formId) {
	document.querySelectorAll('.upload-form').forEach(function(el) {
		el.style.display = "none";
	});
	const form = document.getElementById(formId);
	form.style.display = form.offsetHeight == 0 ? "inherit" : "none";
	form.reset();
	removeImage();
	document.getElementById('uploadProgress').style.display = "none";
}

function showAvatarResetDate(e) {
	const val = e.valueAsNumber || parseInt(e.value) || 3;
	let d = new Date();
	d.setDate(d.getDate() + val);
	e.parentElement.querySelector('span').innerText = d.toLocaleDateString();
}

function checkLoginStatus() {
	return new Promise(function(resolve, reject) {
		let req = new XMLHttpRequest();
		req.open('GET', 'set_temp_avatar.php?status');

		req.onload = function() {
			// This is called even on 404 etc
			// so check the status
			console.log("onload", req);
			if (req.status == 200) {
				// Resolve the promise with the response text
				//resolve(req.response);
				let result = req.response;
				if (result.length < 1) {
					var error = new Error("No response");
					error.name = "NoResponse";
					reject(error);
				}
				try {
					result = JSON.parse(result);
				} catch (err) {
					reject(err);
					return;
				}
				resolve(result);
			} else {
				// Otherwise reject with the status text
				// which will hopefully be a meaningful error
				reject(Error(req.statusText));
			}
		};

		// Handle network errors
		req.onerror = function() {
			console.error("Network error");
			reject(Error('Network Error'));
		};
		// Make the request
		req.send();
	});
}

function transitionEndEventName () {
	var i,
		undefined,
		el = document.createElement('div'),
		transitions = {
			'transition':'transitionend',
			'OTransition':'otransitionend',  // oTransitionEnd in very old Opera
			'MozTransition':'transitionend',
			'WebkitTransition':'webkitTransitionEnd'
		};

	for (i in transitions) {
		if (transitions.hasOwnProperty(i) && el.style[i] !== undefined) {
			return transitions[i];
		}
	}

	//TODO: throw 'TransitionEnd event is not supported in this browser';
}

function initFileUpload() {
	document.getElementById('showUploadForm').addEventListener('click', e => {
		initUploadForm('manuallyAddAvatarForm');
	});
	document.getElementById('addTempAvatar').addEventListener('click', e => {
		document.getElementById('loadingLoginStatus').classList.remove('hidden');
		checkLoginStatus().then(result => {
			document.getElementById('loadingLoginStatus').classList.add('hidden');
			console.log("Authentication status: ", result, !!result.authenticated);
			if(result.error) {
				console.error(`Error checking authentication status: ${result.error.message}`);
				return;
			}
			if (!!result.authenticated) {
				initUploadForm('uploadTempAvatar');
				document.getElementById('uploadTempAvatar').querySelector('textarea').maxlength = result.maxPostLength;
			} else {
				showLoginForm(result.authUrl);
			}
		}, error => {
			console.error("Error checking authentication status", error);
		});
	});
	document.getElementById('cbShouldPostAvatar').addEventListener('click', e => {
		document.getElementById('uploadTempAvatar').querySelector('.posttext').style.display = e.target.checked ? 'inherit' : 'none';
	});
	document.querySelectorAll('.posttext').forEach(el => {
		el.addEventListener('focus', e => {
			if (e.target.selectionStart == e.target.selectionEnd && !document.firstTextboxFocus) {
				document.firstTextboxFocus = true;
				setTimeout(function() {
					console.log("Selecting start", e, e.target);
					e.target.selectionStart = 0;
					e.target.selectionEnd = 0;
				});
			}
		});
	});
	const durationInput = document.querySelector('#uploadTempAvatar input[name=avatarDuration]');
	showAvatarResetDate(durationInput);
	durationInput.addEventListener('change', e => {
		showAvatarResetDate(e.target);
	});
	var isAdvancedUpload = function() {
		var div = document.createElement('div');
		return (('draggable' in div) || ('ondragstart' in div && 'ondrop' in div)) && 'FormData' in window && 'FileReader' in window;
	}();
	if (isAdvancedUpload) {
		window.droppedFile = false;
		const dragOverEvents = ['dragover', 'dragenter'];
		const dragEndEvents = ['dragleave', 'dragend', 'drop'];
		const events = dragOverEvents.concat(dragEndEvents).concat(['drag', 'dragstart']);

		const zone = document.querySelectorAll('.file-upload').forEach(function(form) {
			form.classList.add('advanced-upload');
			const fileSelect = form.querySelector('input[type=file]');
			events.forEach(event => {
				form.addEventListener(event, e => {
					// preventing the unwanted behaviours
					e.preventDefault();
					e.stopPropagation();
				});
			});
			dragOverEvents.forEach(event => {
				form.addEventListener(event, e => {
					form.classList.add('is-dragover');
				});
			});
			dragEndEvents.forEach(event => {
				form.addEventListener(event, e => {
					form.classList.remove('is-dragover');
				});
			});
			form.addEventListener('drop', e => {
				imageAdded(e.dataTransfer.files, e);
			});
			fileSelect.addEventListener('change', e => {
				imageAdded(e.target.files, e);
			});
		});
	}
	console.log(document.querySelectorAll('.removeImage'));
	document.querySelectorAll('.removeImage').forEach(function(el) {
		el.style.zIndex = 1000;
		el.addEventListener('click', e => {
			removeImage();
		});
	});
}

function removeImage(e) {
	console.log(e);
	window.droppedFile = null;
	//document.getElementById('removeImage').style.display = "none";
	document.querySelectorAll('.removeImage').forEach(function(el) {
		el.style.display = "none";
	});
	document.querySelectorAll('.avatarPreview').forEach(function(el) {
		window.URL.revokeObjectURL(el.src);
		el.style.display = "none";
		el.src = "";
	});
}

function handleManualAvatarUpload(e) {
	startUpload(e).then(result => {
		notify("Avatar added successfully", {type: "success"});
		showNewlyAddedPicture(result);
		e.style.display = "none";
	}, error => {
		notify(`Error saving avatar: ${error.message}`, {type: "error"});
		e.style.display = "none";
	});
	return false;
}

function handleTempAvatarUpload(e) {
	startUpload(e).then(result => {
		if (result.warn) {
			notify(result.warn, {type: "warn"});
		} else {
			notify("Your temporary theme avatar has been saved succesfully", {type: "success"});
		}
		e.style.display = "none";
	}, error => {
		console.error(error);
		notify(`Error saving avatar: ${error.message}`, {type: "error"});
	});
	return false;
}

function startUpload(e) {
	console.log(window.droppedFile, e);
	const progress = e.querySelector('.uploadProgress');

	return new Promise(function(resolve, reject) {
		postForm(e, (position, total) => {
			progress.max = total;
			progress.value = position;
			progress.style.display = "inherit";
		}).then(result => {
			if (result.length < 1) {
				reject({'message': 'Received no response from server :( '});
				return;
			}
			try {
				result = JSON.parse(result);
			} catch (err) {
				reject({'message': `Unknown response from server: ${result}`});
				return;
			}
			console.log("Done", result);
			if (result.error) {
				reject(result.error);
			} else {
				resolve(result);
			}
		}, error => {
			console.error(error);
			let serverError;
			if (typeof(error) == "object") {
				serverError = error;
			} else {
				try {
					serverError = JSON.parse(error);
				} catch (err) {
					serverError = {message: "Unknown error"};
				}
			}
			reject(serverError);
		});
	});
}

function showNewlyAddedPicture(postDetails) {
	// TODO: Consolidate together with getUserDetails()
	// TODO: Check if user already has a picture for this theme
	document.querySelector('.avatar-grid').appendChild(createPostBox(info));
}

function createPostBox(info) {
	/*
	 * info.succes:     true (hopefully)
	 * info.error:         Error object, containing "code" and "message"
	 * info.src:         Avatar image
	 * info.presence:     -1: gray, 0: red, 1: green
	 * info.user:         @username. Might be null or empty string
	 * info.realname:     Realname. Might be null or empty string
	 * info.posttext:     HTML or pure text content of the post
	 * info.postid:     ID of the post
	 * info.timestamp:     timestamp of the post
	 */
	console.log(info);
	const grid = document.querySelector('.avatar-grid');
	let postBox = null;
	// If there is already oen in the grid, clone that
	if (grid.querySelectorAll(".avatar-box").length) {
		postBox = grid.children[grid.children.length - 1].cloneNode(true);
	} else {
		console.error("No images in grid yet. Not fully implemented. TODO");
	}

	// New image
	postBox.querySelector('.avatar').src = info.img;

	// User info
	const userDetails = postBox.querySelector('.user-box');

	if (info.realname != null) {
		userDetails.innerHTML = '<span>' + info.realname + '</span><span class="username">' + info.user + '</span>';
	} else {
		userDetails.innerHTML = '<span>' + info.user + '</span>';
	}
/*
	console.log(userDetails.outerHTML);
	let userBox = userDetails.querySelector('.username');
	if (userBox == null) {
		userBox = userDetails.querySelector('span');
	}
	console.log(userBox.outerHTML);
	userBox.innerText = info.user;
	console.log(userBox.outerHTML);

	if (info.realname != null) {
		userBox.innerHTML = '<span>' + info.realname + '</span><span class="username">' + info.user + '</span>';
	}*/
	let presenceIndicator = userDetails.querySelector('.presence-indicator');
	if (presenceIndicator == null) {
		presenceIndicator = document.createElement('div');
		presenceIndicator.classList.add('presence-indicator');
		userDetails.appendChild(presenceIndicator);
	}
	switch (info.presence) {
		case -1:
			presenceIndicator.style.borderColor = "gray";
			presenceIndicator.style.setProperty('border-color', 'var(--gray-dark)');
			break;
		case 0:
			presenceIndicator.style.borderColor = "red";
			presenceIndicator.style.setProperty('border-color', 'var(--red)');
			break;
		case 1:
			presenceIndicator.style.borderColor = "green";
			presenceIndicator.style.setProperty('border-color', 'var(--green)');
			break;
	}

	// Post info
	const postTextBox = postBox.querySelector('.post-text-box');
	postTextBox.innerHTML = info.posttext;

	const postMetaBox = postBox.querySelector('.post-meta-box');
	const postLink = postMetaBox.querySelector('a');
	postLink.href = "https://posts.pnut.io/" + info.postid;
	postLink.innerText = '#' + info.postid;
	let d = new Date(info.timestamp * 1000);
	postMetaBox.querySelector('.postdate').innerText = d.toLocaleString();
	return postBox;
}

function postForm(form, progressCallback) {
	// Return a new promise.
	console.log('Form: ', form);
	return new Promise(function(resolve, reject) {
		//const promise = new Promise();
		if (form.id == 'manuallyAddAvatarForm') {
			const idInput = form.querySelector('[name=postID]');
			const pID = getPostID(idInput);
			if (pID == -1) {
				reject("Invalid post id");
			} else {
				idInput.value = pID;
			}
		}

		var ajaxData = new FormData(form);
		if (window.droppedFile) {
			ajaxData.append(form.querySelector('input[type=file]').getAttribute('name'), window.droppedFile);
		}
		const id = getQueries().id;
		if (!id) {
			reject("Unknown theme id");
		} else {
			ajaxData.append('theme', id);
			ajaxData.append('submit', 'submit');
			console.log(ajaxData);
			// Do the usual XHR stuff
			let req = new XMLHttpRequest();
			req.open(form.method, form.action);

			req.onload = function() {
				// This is called even on 404 etc
				// so check the status
				console.log("onload", req);
				if (req.status == 200) {
					// Resolve the promise with the response text
					resolve(req.response);
				}
				else {
					// Otherwise reject with the status text
					// which will hopefully be a meaningful error
					reject(Error(req.statusText));
				}
			};

			// Handle network errors
			req.onerror = function() {
				console.error("Network error");
				reject(Error('Network Error'));
			};
			if (progressCallback) {
				var eventSource = req.upload || req;
				eventSource.addEventListener("progress", function(e) {
					// normalize position attributes across XMLHttpRequest versions and browsers
					var position = e.position || e.loaded;
					var total = e.totalSize || e.total;
					progressCallback(position, total);
				});
			}

			// Make the request
			req.send(ajaxData);
		}
	});
}

function imageAdded(arr, evt) {
	if (!arr.length) {
		return;
	}
	console.log("Dropped image", arr, evt);
	window.droppedFile = arr[0];
	const imgSize = window.droppedFile.size;
	console.log("Size in Bytes", imgSize);
	const maxSize = parseInt(document.querySelector('input[name=MAX_FILE_SIZE]').value);
	let errorSpan = document.getElementById('imgTooLarge');
	if (imgSize > maxSize) {
		//<span style="display: block;">Image too large</span>
		if (errorSpan == null) {
			errorSpan = document.createElement('span');
			errorSpan.classList.add('imgTooLarge');
			errorSpan.innerText = `Image is too large. It is ${(imgSize/1024/1024).toFixed(2)}MiB, but should be <= ${(maxSize/1024/1024).toFixed(2)}MiB`;
			errorSpan.style.display = 'inherit';
			errorSpan.id = 'imgTooLarge';
			document.querySelector('#uploadTempAvatar table tr td:nth-child(2)').appendChild(errorSpan);
		} else {
			errorSpan.style.display = 'inherit';
		}
	} else if (errorSpan != null) {
		errorSpan.style.display = 'none';
	}
	getOrientation(function(e){
		console.log("Orientation", e);
		let prv = evt.target.parentElement.querySelector('.avatarPreview');
		switch (e) {
			case 1:
				prv.style.transform = "rotate(0)";
				break;
			case 3:
				prv.style.transform = "rotate(180deg)";
				break;
			case 6:
				prv.style.transform = "rotate(90deg)";
				break;
			case 8:
				prv.style.transform = "rotate(270deg)";
				break;
			default:
				prv.style.transform = "rotate(0)";
				break;
		}
		if (prv.src) {
			window.URL.revokeObjectURL(prv.src);
		}
		prv.style.display = "inherit";
		prv.src = window.URL.createObjectURL(droppedFile);
		evt.target.parentElement.querySelector('.removeImage').style.display = "inherit";
		evt.target.parentElement.querySelector('.removeImage').style.zIndex = 1000;zIndex = 1000;
	});
}

function getOrientation(callback) {
	var reader = new FileReader();
	reader.onload = function(e) {
		var view = new DataView(e.target.result);
		const magic = view.getUint16(0, false);
		if (magic != 0xFFD8) {
			console.warn("Unknown magic bytes: ", magic.toString(16))
			return callback(-2);
		}
		var length = view.byteLength, offset = 2;
		console.debug("Length: ", length);
		while (offset < length) {
			const firstBytesTest = view.getUint16(offset+2, false);
			if (firstBytesTest <= 8) {
				console.warn("firstBytesTest <=8", firstBytesTest);
				return callback(-1);
			}
			var marker = view.getUint16(offset, false);
			offset += 2;
			if (marker == 0xFFE1) {
				console.debug("Found marker");
				if (view.getUint32(offset += 2, false) != 0x45786966) {
					console.debug("Invalid sequence following marker: ", view.getUint32(offset += 2, false).toString(16));
					return callback(-1);
				}

				var little = view.getUint16(offset += 6, false) == 0x4949;
				offset += view.getUint32(offset + 4, little);
				var tags = view.getUint16(offset, little);
				offset += 2;
				for (var i = 0; i < tags; i++) {
					if (view.getUint16(offset + (i * 12), little) == 0x0112) {
						console.debug("Found rotation tag");
						return callback(view.getUint16(offset + (i * 12) + 8, little));
					}
				}
			} else if ((marker & 0xFF00) != 0xFF00) {
				break;
			} else {
				offset += view.getUint16(offset, false);
			}
		}
		return callback(-1);
	};
	reader.readAsArrayBuffer(window.droppedFile);
}

function setupUploadPostPreview() {
	const postIdInput = document.querySelector('input[name=postID]');
	window.lastPostIDKey = 0;
	postIdInput.onkeyup = function() {
		window.lastPostIDKey = Date.now();
		setTimeout(function() {
			const now = Date.now();
			const diff = now - window.lastPostIDKey;
			console.log(diff);
			if (diff < 500) {
				return;
			}
			const pID = getPostID(postIdInput);
			get(`get_posttext.php?id=${pID}&avatarWidth=40`).then(function(response) {
				try {
					response = JSON.parse(response);
				} catch (error) {
					showError(`Unknown response from server: ${response}`);
					return;
				}
				if (response.error) {
					showError(`Error loading post #${pID}: ${response.error}`);
					return;
				}
				const tbl = document.querySelector('.upload-form').querySelector('table');
				let i = tbl.rows[1].cells.length - 1;
				// Remove existing post boxes
				while (tbl.rows[1].cells[i].querySelector('.post-box')) {
					tbl.rows[1].removeChild(tbl.rows[1].cells[i]);
					i = tbl.rows[1].cells.length - 1;
				}
				const cell = tbl.rows[1].insertCell();
				const postBox = createPostBox(response);
				const ab = postBox.querySelector('.avatar');
				ab.style.width = '20px';
				postBox.removeChild(ab.parentElement);
				const ub = postBox.querySelector('.post-box').querySelector('.user-box');
				ub.insertBefore(ab, ub.firstChild);
				ab.className = "";
				ab.style.borderRadius = "3px";
				cell.style.verticalAlign = 'top';
				cell.appendChild(postBox);
				// Post box overflows horizontically (long links, etc). Remove set width and let it goooo
				if (postBox.scrollWidth > postBox.clientWidth) {
					postBox.style.width = "initial";
				}
			});
		}, 500);
	};
}

function getPostID(input) {
	const parsed = parseInt(input.value);
	if (isNaN(parsed)) {
		matches = input.value.match(/(?:https?:\/\/)?((posts.*pnut.*)|.*pnut.*posts)\/(\d+)/);
		if (!matches || Number.isInteger(matches[matches.length-1])) {
			return -1;
		}
		return parseInt(matches[matches.length-1]);
	}
	return parsed;
}

function showError(message, params = {}) {
	params.type = 'error';
	notify(message, params);
}

function notify(message, params) {
	defaultOptions = {
		class: 'notif',
		position: 'top|right',
		duration: 5,
		type: 'info'
	};
	const mergedOptions = {
		...defaultOptions,
		  ...params,
	};
	mergedOptions.duration *= 1000;
	switch (mergedOptions.type) {
		case 'success':
			console.log(message);
			toast.success(message, mergedOptions);
			break;
		case 'warn':
			console.warn(message);
			toast.warn(message, mergedOptions);
			break;
		case 'error':
			console.error(message);
			toast.alert(message, mergedOptions);
			break;
		default:
			console.log(message);
			toast.message(message, mergedOptions);
			break;
	}
}
