// @ts-check
const default_theme = "classic.css";
const theme_storage_key = "jspaint theme";
const disable_seasonal_theme_key = "jspaint disable seasonal theme";
const href_for = (theme) => `styles/themes/${theme}`;

let iid;
function wait_for_theme_loaded(theme, callback) {
	clearInterval(iid);
	iid = setInterval(() => {
		const theme_loaded =
			getComputedStyle(document.documentElement)
				.getPropertyValue("--theme-loaded")
				.replace(/['"]+/g, "").trim();
		if (theme_loaded === theme) {
			clearInterval(iid);
			callback();
		}
	}, 15);
}

let grinch_button;
let current_theme;
try {
	const grinch = localStorage[disable_seasonal_theme_key] === "true";
	const is_december = new Date().getMonth() === 11;
	if (is_december && !grinch) {
		current_theme = "winter.css"; // overriding theme preference until you disable the seasonal theme
		wait_for_theme_loaded(current_theme, () => { // could just wait for DOM to load, but theme is needed for the button styling
			make_grinch_button();
		});
	} else {
		current_theme = localStorage[theme_storage_key] || default_theme;
	}
} catch (error) {
	console.error(error);
	current_theme = default_theme;
}

const theme_link = document.createElement("link");
theme_link.rel = "stylesheet";
theme_link.type = "text/css";
theme_link.href = href_for(current_theme);
theme_link.id = "theme-link";
document.head.appendChild(theme_link);

update_not_for_modern_theme();

const get_theme = () => current_theme;

const set_theme = (theme) => {
	current_theme = theme;

	try {
		localStorage[theme_storage_key] = theme;
		localStorage[disable_seasonal_theme_key] = "true"; // any theme change disables seasonal theme (unless of course you select the seasonal theme)
		grinch_button?.remove();
	} catch (_error) { /* ignore */ }

	const signal_theme_load = () => {
		$(window).triggerHandler("theme-load");
		$(window).trigger("resize"); // not exactly, but get dynamic cursor to update its offset
	};

	wait_for_theme_loaded(theme, signal_theme_load);
	theme_link.href = href_for(theme);

	update_not_for_modern_theme();

	signal_theme_load();
};

function update_not_for_modern_theme() {
	const not_for_modern = /** @type {NodeListOf<HTMLLinkElement>} */(document.querySelectorAll("link.not-for-modern"));
	for (const link of not_for_modern) {
		link.disabled = current_theme === "modern.css" || current_theme === "modern-dark.css" || current_theme === "bubblegum.css";
	}
}

function make_grinch_button() {
	const button = document.createElement("button");
	button.ariaLabel = "Disable seasonal theme";
	button.className = "grinch-button";
	let clicked = false;
	let smile = 0;
	let momentum = 0;
	let smile_target = 0;
	let anim_id;
	const num_frames = 38;
	const frame_width = 100;
	button.onclick = () => {
		if (smile === smile_target) {
			steal_christmas();
		}
		clicked = true;
	};
	const start_smile = button.onmouseleave = () => {
		smile_target = clicked ? 1 : 0;
		animate();
		document.removeEventListener("touchmove", document_touchmove);
	};
	const stop_smile = button.onmouseenter = () => {
		smile_target = 1;
		momentum = Math.max(momentum, 0.02); // for the immediacy of the hover effect
		animate();
	};
	button.onpointerdown = (event) => {
		if (event.pointerType === "touch") {
			start_smile();
			document.addEventListener("touchmove", document_touchmove);
		}
	};
	// Not using pointerleave because it includes when the finger is lifted off the screen
	// Maybe it would be easier to detect that case with event.button(s) though.
	function document_touchmove(event) {
		var touch = event.touches[0];
		if (button !== document.elementFromPoint(touch.pageX, touch.pageY)) {
			// finger left the button
			clicked = false;
			stop_smile();
		}
	}

	function animate() {
		cancelAnimationFrame(anim_id);
		smile += momentum * 0.5;
		momentum *= 0.9; // set to 0.99 to test smile getting stuck (should be fixed)
		if (smile_target) {
			momentum += 0.001;
		} else {
			if (smile < 0.4) {
				momentum -= 0.0005; // slowing down the last bit of un-smiling (feels more natural; I wish there were more frames though)
			} else {
				momentum -= 0.001;
			}
		}
		if (smile > 1) {
			smile = 1;
			momentum = 0;
			if (clicked) {
				steal_christmas();
			}
		} else if (smile < 0) {
			smile = 0;
			momentum = 0;
		}
		if (smile !== smile_target) {
			anim_id = requestAnimationFrame(animate);
		}
		button.style.backgroundPosition = `${-Math.floor(smile * (num_frames - 1)) * frame_width}px 0px`;
	}
	function on_zoom_etc() {
		// scale to nearest pixel-perfect size
		button.style.transform = `scale(${Math.max(1, Math.floor(devicePixelRatio)) / devicePixelRatio})`;
		button.style.transformOrigin = "bottom right";
		button.style.imageRendering = "pixelated";
	}
	window.addEventListener("resize", on_zoom_etc);
	on_zoom_etc();
	function steal_christmas() {
		let new_theme;
		try {
			localStorage[disable_seasonal_theme_key] = "true";
			new_theme = localStorage[theme_storage_key] || default_theme;
		} catch (_error) { /* ignore */ }
		if (new_theme === "winter.css") {
			new_theme = default_theme;
		}
		set_theme(new_theme);
		button.remove();
		window.removeEventListener("resize", on_zoom_etc);
		document.removeEventListener("touchmove", document_touchmove);
	}
	document.body.appendChild(button);
	grinch_button = button;
}

export { get_theme, set_theme };

