import { sessionId } from "./persist.js";
import { safe } from "./safe.js";
import type { TelemetryEvent } from "./types.js";

const buffer: TelemetryEvent[] = [];
let eventsUrl: string | undefined;
let key = "";
let listener: ((event: TelemetryEvent) => void) | undefined;

export function initEvents(publicKey: string, url?: string): void {
	key = publicKey;
	eventsUrl = url;
	buffer.length = 0;
}

export function onTelemetry(
	handler: ((event: TelemetryEvent) => void) | undefined,
): void {
	listener = handler;
}

export function emit(
	event: Omit<TelemetryEvent, "sessionId"> & { sessionId?: string },
): void {
	const full: TelemetryEvent = {
		...event,
		sessionId: event.sessionId ?? sessionId(key),
	};
	buffer.push(full);
	listener?.(full);
}

export function pendingEvents(): readonly TelemetryEvent[] {
	return buffer;
}

export function flushEvents(): void {
	if (!eventsUrl || buffer.length === 0) return;
	const payload = JSON.stringify({
		key,
		events: buffer.splice(0, buffer.length),
	});
	const blob = new Blob([payload], { type: "text/plain" });
	const sent = safe(
		() => navigator.sendBeacon?.(eventsUrl as string, blob) ?? false,
		false,
	);
	if (sent) return;
	safe(() => {
		void fetch(eventsUrl as string, {
			method: "POST",
			body: payload,
			headers: { "content-type": "text/plain" },
			keepalive: true,
		});
	}, undefined);
}

export function listenVisibilityFlush(): () => void {
	const onHide = () => {
		if (document.visibilityState === "hidden") flushEvents();
	};
	document.addEventListener("visibilitychange", onHide);
	return () => document.removeEventListener("visibilitychange", onHide);
}
