<script setup lang="ts">
import { $i } from "@/i.js";
import { computed, onMounted, onUnmounted, ref } from "vue";

const generateRandomClass = () => {
	const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
	let result = "";
	for (let i = 0; i < 8; i++) {
		result += chars.charAt(Math.floor(Math.random() * chars.length));
	}
	return result;
};

const containerClass = ref(generateRandomClass());
const recreationKey = ref(0);
let regenerationInterval: ReturnType<typeof setInterval> | null = null;
let checkInterval: ReturnType<typeof setInterval> | null = null;
let styleElement: HTMLStyleElement | null = null;
let watermarkElement: HTMLDivElement | null = null;
let mutationObserver: MutationObserver | null = null;
let headObserver: MutationObserver | null = null;
let attributeObserver: MutationObserver | null = null;
let allCreatedClasses: string[] = [];

const encodeTextToPath = (text: string) => {
	const charPaths: { [key: string]: string } = {
		a: "M2,8 L4,2 L6,2 L8,8 M3,6 L7,6",
		b: "M2,2 L2,8 L6,8 C7,8 8,7 8,6 C8,5 7,4 6,4 L6,4 C7,4 8,3 8,2 C8,1 7,2 6,2 Z",
		c: "M8,3 C7,2 6,2 5,2 C3,2 2,3 2,5 C2,7 3,8 5,8 C6,8 7,8 8,7",
		d: "M2,2 L2,8 L5,8 C7,8 8,7 8,5 C8,3 7,2 5,2 Z",
		e: "M2,2 L2,8 L8,8 M2,2 L8,2 M2,5 L6,5",
		f: "M2,2 L2,8 M2,2 L8,2 M2,5 L6,5",
		g: "M8,3 C7,2 6,2 5,2 C3,2 2,3 2,5 C2,7 3,8 5,8 L8,8 L8,5 L5,5",
		h: "M2,2 L2,8 M8,2 L8,8 M2,5 L8,5",
		i: "M3,2 L7,2 M5,2 L5,8 M3,8 L7,8",
		j: "M8,2 L8,7 C8,8 7,8 6,8 C5,8 4,8 4,7",
		k: "M2,2 L2,8 M8,2 L2,5 M4,5 L8,8",
		l: "M2,2 L2,8 L8,8",
		m: "M2,8 L2,2 L5,5 L8,2 L8,8",
		n: "M2,8 L2,2 L8,8 L8,2",
		o: "M2,3 C2,2 3,2 5,2 C7,2 8,2 8,3 L8,7 C8,8 7,8 5,8 C3,8 2,8 2,7 Z",
		p: "M2,2 L2,8 M2,2 L6,2 C7,2 8,3 8,4 C8,5 7,6 6,6 L2,6",
		q: "M2,3 C2,2 3,2 5,2 C7,2 8,2 8,3 L8,7 C8,8 7,8 5,8 C3,8 2,8 2,7 Z M6,6 L8,8",
		r: "M2,2 L2,8 M2,2 L6,2 C7,2 8,3 8,4 C8,5 7,6 6,6 L2,6 M6,6 L8,8",
		s: "M8,3 C7,2 5,2 5,2 C3,2 2,3 2,4 C2,5 3,5 5,5 C7,5 8,6 8,7 C8,8 7,8 5,8 C3,8 2,7 2,7",
		t: "M2,2 L8,2 M5,2 L5,8",
		u: "M2,2 L2,7 C2,8 3,8 5,8 C7,8 8,8 8,7 L8,2",
		v: "M2,2 L5,8 L8,2",
		w: "M2,2 L3,8 L5,5 L7,8 L8,2",
		x: "M2,2 L8,8 M8,2 L2,8",
		y: "M2,2 L5,5 L8,2 M5,5 L5,8",
		z: "M2,2 L8,2 L2,8 L8,8",
		" ": "",
		"0": "M2,3 C2,2 3,2 5,2 C7,2 8,2 8,3 L8,7 C8,8 7,8 5,8 C3,8 2,8 2,7 Z M2,2 L8,8",
		"1": "M4,2 L5,2 L5,8 M3,8 L7,8",
		"2": "M2,3 C2,2 3,2 5,2 C7,2 8,2 8,3 C8,4 7,5 5,5 L2,8 L8,8",
		"3": "M2,2 L8,2 C8,2 8,3 8,4 C8,5 7,5 5,5 C7,5 8,5 8,6 C8,7 8,8 8,8 L2,8",
		"4": "M2,2 L2,5 L8,5 M6,2 L6,8",
		"5": "M8,2 L2,2 L2,5 L6,5 C7,5 8,6 8,7 C8,8 7,8 5,8 C3,8 2,7 2,7",
		"6": "M8,2 C7,2 5,2 5,2 C3,2 2,3 2,5 L2,7 C2,8 3,8 5,8 C7,8 8,7 8,6 C8,5 7,5 5,5 L2,5",
		"7": "M2,2 L8,2 L5,8",
		"8": "M5,2 C3,2 2,3 2,4 C2,5 3,5 5,5 C7,5 8,5 8,4 C8,3 7,2 5,2 Z M5,5 C3,5 2,6 2,7 C2,8 3,8 5,8 C7,8 8,7 8,6 C8,5 7,5 5,5 Z",
		"9": "M8,5 C8,3 7,2 5,2 C3,2 2,3 2,4 C2,5 3,5 5,5 L8,5 L8,7 C8,8 7,8 5,8 C3,8 2,7 2,7",
	};

	let path = "";
	const chars = text.toLowerCase().split("");
	let xOffset = 0;

	chars.forEach((char, index) => {
		if (charPaths[char]) {
			const translatedPath = charPaths[char]
				.replace(/([ML])\s*(\d+),(\d+)/g, (match, command, x, y) => {
					return `${command}${parseInt(x) + xOffset},${y}`;
				})
				.replace(
					/([C])\s*(\d+),(\d+)\s+(\d+),(\d+)\s+(\d+),(\d+)/g,
					(match, command, x1, y1, x2, y2, x3, y3) => {
						return `${command}${parseInt(x1) + xOffset},${y1} ${parseInt(x2) + xOffset},${y2} ${parseInt(x3) + xOffset},${y3}`;
					},
				);
			path += translatedPath + " ";
		}
		xOffset += 7;
	});

	return path.trim();
};

const regenerateWatermark = () => {
	cleanupOldElements();
	containerClass.value = generateRandomClass();
	recreationKey.value++;
	allCreatedClasses.push(containerClass.value);
	createStyleElement();
};

const cleanupOldElements = () => {
	const allStyles = document.head.querySelectorAll("style");
	allStyles.forEach((style) => {
		const content = style.textContent || "";
		const hasOldClasses = allCreatedClasses.some(
			(className) =>
				content.includes(className) && className !== containerClass.value,
		);
		if (hasOldClasses) {
			style.remove();
		}
	});

	allCreatedClasses = [containerClass.value];
};

const createStyleElement = () => {
	if (styleElement && styleElement.parentNode) {
		styleElement.parentNode.removeChild(styleElement);
	}

	styleElement = document.createElement("style");

	const fgColor = getComputedStyle(document.documentElement).getPropertyValue('--MI_THEME-fg').trim() || '#000000';

	const svgContent = `<svg viewBox="0 0 ${textWidth.value} 10" xmlns="http://www.w3.org/2000/svg"><path d="${pathData.value}" stroke="${fgColor}" fill="none" stroke-width="0.8"/></svg>`;
	const encodedSvg = encodeURIComponent(svgContent);

	const styles = `
        .${containerClass.value} {
            position: fixed !important;
            top: 0 !important;
            left: 0 !important;
            width: 100vw !important;
            height: 100vh !important;
            pointer-events: none !important;
            z-index: 999999999 !important;
            overflow: hidden !important;
            opacity: 0.02 !important;
            background-image: url("data:image/svg+xml,${encodedSvg}") !important;
            background-repeat: repeat !important;
            background-size: 80px 16px !important;
            background-position: 10px 10px !important;
        }
    `;

	styleElement.textContent = styles;
	
	Object.defineProperty(styleElement, 'remove', {
		value: () => {
			setTimeout(() => {
				if (!styleElement?.parentNode) {
					document.head.appendChild(styleElement!);
				}
			}, 0);
		},
		writable: false,
		configurable: false,
	});

	document.head.appendChild(styleElement);
};

const ensureWatermarkExists = () => {
	if (!watermarkElement || !document.body.contains(watermarkElement)) {
		const newElement = document.createElement('div');
		newElement.className = containerClass.value;
		newElement.setAttribute('data-watermark', 'true');
		
		Object.defineProperty(newElement, 'remove', {
			value: () => {
				setTimeout(() => {
					if (!document.body.contains(newElement)) {
						document.body.appendChild(newElement);
					}
				}, 0);
			},
			writable: false,
			configurable: false,
		});

		const originalStyleSetter = Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'style')?.set;
		if (originalStyleSetter) {
			Object.defineProperty(newElement, 'style', {
				get: () => {
					return newElement.getAttribute('style') || '';
				},
				set: (value) => {
					return;
				},
			});
		}

		document.body.appendChild(newElement);
		watermarkElement = newElement;
		
		startAttributeObserver();
	} else if (watermarkElement.className !== containerClass.value) {
		watermarkElement.className = containerClass.value;
	}

	if (!styleElement || !document.head.contains(styleElement)) {
		createStyleElement();
	}
};

const startAttributeObserver = () => {
	if (attributeObserver) {
		attributeObserver.disconnect();
	}

	if (!watermarkElement) return;

	attributeObserver = new MutationObserver((mutations) => {
		for (const mutation of mutations) {
			if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
				if (watermarkElement && watermarkElement.className !== containerClass.value) {
					watermarkElement.className = containerClass.value;
				}
			} else if (mutation.type === 'attributes' && mutation.attributeName === 'style') {
				if (watermarkElement) {
					const style = watermarkElement.getAttribute('style');
					if (style && (style.includes('display') || style.includes('visibility') || style.includes('opacity'))) {
						watermarkElement.removeAttribute('style');
					}
				}
			}
		}
	});

	attributeObserver.observe(watermarkElement, {
		attributes: true,
		attributeOldValue: true,
	});
};

const startMutationObserver = () => {
	mutationObserver = new MutationObserver((mutations) => {
		for (const mutation of mutations) {
			if (mutation.type === 'childList') {
				mutation.removedNodes.forEach((node) => {
					if (node === watermarkElement || node === styleElement) {
						ensureWatermarkExists();
					}
				});
			}
		}
	});

	mutationObserver.observe(document.body, {
		childList: true,
		subtree: true,
	});

	headObserver = new MutationObserver((mutations) => {
		for (const mutation of mutations) {
			if (mutation.type === 'childList') {
				mutation.removedNodes.forEach((node) => {
					if (node === styleElement) {
						ensureWatermarkExists();
					}
				});
			}
		}
	});

	headObserver.observe(document.head, {
		childList: true,
		subtree: true,
	});
};

const watermarkText = computed(() => $i?.id || "not signed in");
const pathData = computed(() => encodeTextToPath(watermarkText.value));
const textWidth = computed(() => watermarkText.value.length * 7 + 10);

onMounted(() => {
	allCreatedClasses.push(containerClass.value);
	createStyleElement();
	ensureWatermarkExists();
	startMutationObserver();

	checkInterval = setInterval(() => {
		ensureWatermarkExists();
	}, 100);

	regenerationInterval = setInterval(() => {
		regenerateWatermark();
	}, 5000);
});

onUnmounted(() => {
	if (checkInterval) {
		clearInterval(checkInterval);
	}
	if (regenerationInterval) {
		clearInterval(regenerationInterval);
	}
	if (mutationObserver) {
		mutationObserver.disconnect();
	}
	if (headObserver) {
		headObserver.disconnect();
	}
	if (attributeObserver) {
		attributeObserver.disconnect();
	}
	cleanupOldElements();
	if (styleElement && styleElement.parentNode) {
		styleElement.parentNode.removeChild(styleElement);
	}
	if (watermarkElement && watermarkElement.parentNode) {
		watermarkElement.parentNode.removeChild(watermarkElement);
	}
});
</script>

<template>
	<div style="display: none;" :key="`watermark-${recreationKey}`"></div>
</template>
