// the emitter setup
// TODO: validate if we want to add event back in later..
// let emitFn: ((roomId: string, event: string, payload: unknown) => void) | null =
// 	null;

import { createLogger } from "../logger/logger.controller.js";

type QueuedPayload = unknown;

let emitFn: ((roomId: string, payload: QueuedPayload[]) => void) | null = null;

const queues = new Map<string, QueuedPayload[]>();
const timers = new Map<string, NodeJS.Timeout>();

const FLUSH_MS = 500;
const MAX_QUEUE_SIZE = 200;

export const registerEmitter = (
	fn: (roomId: string, payload: QueuedPayload) => void,
) => {
	emitFn = fn;
};

export const emitToRoom = (roomId: string, payload: QueuedPayload) => {
	const log = createLogger({ module: "socket.io", subModule: "emitter" });
	if (!emitFn) {
		console.error("Socket emitter not initialized");
		return;
	}

	const queue = queues.get(roomId) ?? [];

	if (queue.length > MAX_QUEUE_SIZE) {
		log.error(
			{ stack: { roomId, size: queue.length }, notify: true },
			`Socket queue exceeded max size for ${roomId}`,
		);
	}
	queue.push(payload);
	queues.set(roomId, queue);

	if (timers.has(roomId)) return;

	const timer = setTimeout(() => {
		try {
			const payloads = queues.get(roomId) ?? [];

			if (payloads.length === 0) return;
			emitFn?.(roomId, payloads);

			queues.delete(roomId);
		} catch (e) {
			console.error("Socket emit failed", { roomId, e });
		} finally {
			timers.delete(roomId);
		}
	}, FLUSH_MS);

	timers.set(roomId, timer);
};

/*
example emitToRoom(room, payload)

payload can be anything json serilized example below.

emitToRoom("inventory:ppoo", {
  type: "snapshot",
  location: "ppoo",
  items,
  createdAt: new Date().toISOString(),
});
*/
