import type {
	AnyLanyardPayload,
	LanyardInitStatePayload,
	LanyardPayload,
	LanyardPresence,
	LanyardPresenceUpdatePayload
} from "types/lanyard";

export class Lanyard {
	private socket: WebSocket;
	private readonly userId: string;
	private readonly updateCallback: (presence: LanyardPresence) => void;
	private heartbeatInterval?: number;

	constructor(
		userId: string,
		updateCallback: (presence: LanyardPresence) => void
	) {
		this.userId = userId;
		this.updateCallback = updateCallback;
		this.socket = new WebSocket("wss://api.lanyard.rest/socket");
		this.initialize();
	}

	private send(data: AnyLanyardPayload) {
		this.socket.send(JSON.stringify(data));
	}

	private initialize() {
		this.socket.onmessage = event => {
			const payload: LanyardPayload = JSON.parse(event.data);
			switch (payload.op) {
				case 1: {
					// Initialize
					this.send({
						op: 2,
						d: {
							subscribe_to_ids: [this.userId]
						}
					});

					this.send({ op: 3 });

					const interval =
						"heartbeat_interval" in payload.d
							? payload.d.heartbeat_interval
							: 30000;

					this.heartbeatInterval = window.setInterval(() => {
						this.send({ op: 3 });
					}, interval);
					break;
				}
				case 0: {
					const typedPayload = payload as
						| LanyardInitStatePayload
						| LanyardPresenceUpdatePayload;

					const presence =
						typedPayload.t === "INIT_STATE"
							? typedPayload.d[this.userId]
							: typedPayload.d;

					this.updateCallback(presence);
					break;
				}
			}
		};
	}

	public close() {
		if (this.heartbeatInterval) {
			clearInterval(this.heartbeatInterval);
		}
		this.socket.close();
	}
}