import { env } from "$env/dynamic/public";

export enum SocketConnectionType {
    NONE = "NONE",
    HOST = "HOST",
    DISPLAY = "DISPLAY"
}

const messages: string[] = $state([]);
let connectionType = $state(SocketConnectionType.NONE);

let socket: WebSocket | undefined;

const connectAsHost = () => {
    if (socket !== undefined) return;
    socket = new WebSocket(
        `${location.protocol === "https:" ? "wss" : "ws"}://${env.PUBLIC_JEOPARDY_SERVER ?? "127.0.0.1:12345"}/websocket`
    );
    socket.addEventListener("open", onOpen(SocketConnectionType.HOST));
    socket.addEventListener("message", onFirstMessage);
    socket.addEventListener("close", onClose);
    socket.addEventListener("error", onError);
};

const connectAsDisplay = () => {
    if (socket !== undefined) return;
    socket = new WebSocket(
        `${location.protocol === "https:" ? "wss" : "ws"}://${env.PUBLIC_JEOPARDY_SERVER ?? "127.0.0.1:12345"}/websocket`
    );
    socket.addEventListener("open", onOpen(SocketConnectionType.DISPLAY));
    socket.addEventListener("message", onFirstMessage);
};

const sendMessage = (obj: unknown) => {
    if (socket === undefined) return;
    if (socket.readyState <= 1) {
        try {
            socket.send(JSON.stringify(obj));
        } catch {
            console.error(`Could not send ${obj}`);
        }
    }
};

function onOpen(type: SocketConnectionType) {
    return async (event: Event) => {
        console.log("Connection established");
        console.log(event);
        if (socket === undefined) return;
        // somehow beeing to fast so have to wait some time
        await new Promise((r) => setTimeout(r, 100));
        socket.send(type.toString());
    };
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
function onFirstMessage(event: MessageEvent<any>) {
    if (socket === undefined) return;
    console.log(event.data);
    if (event.data === SocketConnectionType.HOST) {
        connectionType = SocketConnectionType.HOST;
        socket.removeEventListener("message", onFirstMessage);
        socket.addEventListener("message", onMessage);
    } else if (event.data === SocketConnectionType.DISPLAY) {
        connectionType = SocketConnectionType.DISPLAY;
        socket.removeEventListener("message", onFirstMessage);
        socket.addEventListener("message", onMessage);
    } else {
        console.error("Failed to register");
        socket.close();
        socket = undefined;
    }
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
function onMessage(event: MessageEvent<any>) {
    messages.push(event.data);
}

function onClose(event: CloseEvent) {
    console.log("Connection closed");
    console.log(event);
    connectionType = SocketConnectionType.NONE;
    if (socket === undefined) return;
    socket.close();
    socket = undefined;
}

function onError(event: Event) {
    console.error("Websocket error occured");
    console.error(event);
    connectionType = SocketConnectionType.NONE;
    if (socket === undefined) return;
    socket.close();
    socket = undefined;
}

export default {
    get message() {
        return messages[0];
    },
    nextMessage() {
        return messages.shift();
    },
    get messageNum() {
        return messages.length;
    },
    get connectionType() {
        return connectionType;
    },
    sendMessage,
    connectAsHost,
    connectAsDisplay
};
