import { useCallback, useEffect, useState } from "react";
import socket from "@/lib/socket.io";

type RoomUpdatePayload<T> = {
	roomId: string;
	payloads: T[];
};

type RoomErrorPayload = {
	roomId?: string;
	message?: string;
};

export function useSocketRoom<T>(
	roomId: string,
	getKey?: (item: T) => string | number,
) {
	const [data, setData] = useState<T[]>([]);
	const [info, setInfo] = useState(
		"No data yet — join the room to start receiving",
	);

	const clearRoom = useCallback(
		(id?: string | number) => {
			if (id !== undefined && getKey) {
				setData((prev) => prev.filter((item) => getKey(item) !== id));
				setInfo(`Removed item ${id}`);
				return;
			}

			setData([]);
			setInfo("Room data cleared");
		},
		[getKey],
	);

	useEffect(() => {
		function handleConnect() {
			socket.emit("join-room", roomId);
			setInfo(`Joined room: ${roomId}`);
		}

		function handleUpdate(payload: RoomUpdatePayload<T>) {
			// protects against other room updates hitting this hook
			if (payload.roomId !== roomId) return;

			setData((prev) => [...payload.payloads, ...prev]);
			setInfo("");
		}

		function handleError(err: RoomErrorPayload) {
			if (err.roomId && err.roomId !== roomId) return;
			setInfo(err.message ?? "Room error");
		}

		if (!socket.connected) {
			socket.connect();
		}

		socket.on("connect", handleConnect);
		socket.on("room-update", handleUpdate);
		socket.on("room-error", handleError);

		// If already connected, join immediately
		if (socket.connected) {
			socket.emit("join-room", roomId);
			setInfo(`Joined room: ${roomId}`);
		}

		return () => {
			socket.emit("leave-room", roomId);

			socket.off("connect", handleConnect);
			socket.off("room-update", handleUpdate);
			socket.off("room-error", handleError);
		};
	}, [roomId]);

	return { data, info, clearRoom };
}
