const MOUSE_MOVE_TIMEOUT_MS = 100;

globalThis.Logger = class Logger {
	#abort;
	#mouseMoveTimeout;

	static get url() {
		const url = new URL(window.location);
		url.pathname = "/log";

		return url;
	}

	/**
	 * Return a best-effort unique string that identifies this client
	 * @returns {String}
	 */
	static async #fingerprint() {
		// Create a hash from various identifying browser data
		const buffer = await window.crypto.subtle.digest("SHA-1", new TextEncoder().encode(JSON.stringify([
			navigator.userAgent,
			navigator.buildId,
			navigator.languages
		])));

		return new DataView(buffer).getBigUint64().toString();
	}

	/**
	 * Extract desired MouseEvent data into an object literal
	 * @param {MouseEvent} event 
	 * @returns {Object}
	 */
	static #mouseEvent(event) {
		return {
			e: event.type,
			w: window.innerWidth,
			h: window.innerHeight,
			x: event.x,
			y: event.y
		}
	}

	/**
	 * Extract desired KeyboardEvent data into an object literal
	 * @param {KeyboardEvent} event 
	 * @returns {Object}
	 */
	static #keyEvent(event) {
		return {
			e: event.type,
			c: event.key,
			s: event.shiftKey
		}
	}

	constructor() {}

	/**
	 * Start logging user activities
	 */
	start() {
		this.#abort = new AbortController();

		document.addEventListener("keyup", (event) => this.log(Logger.#keyEvent(event)), { signal: this.#abort.signal });
		document.addEventListener("keydown", (event) => this.log(Logger.#keyEvent(event)), { signal: this.#abort.signal });
		document.addEventListener("click", (event) => this.log(Logger.#mouseEvent(event)), { signal: this.#abort.signal });
		document.addEventListener("mousemove", (event) => {
			// Throttle mousemove events
			clearTimeout(this.#mouseMoveTimeout);
			//this.#mouseMoveTimeout = setTimeout(() => this.#log(mouseEvent(event)), MOUSE_MOVE_TIMEOUT_MS);
		}, { signal: this.#abort.signal });
	}

	/**
	 * Stop logging user activitiers
	 */
	stop() {
		this.#abort.abort();
	}

	/**
	 * Log user data
	 * @param {Object} data 
	 * @returns {Response}
	 */
	async log(data) {
		return await fetch(Logger.url, {
			body: JSON.stringify({
				client: data,
				fingerprint: (await Logger.#fingerprint())
			}),
			method: "POST",
			headers: Object.assign({
				"Content-Type": "application/json"
			}, VV.header)
		});
	};
}