import type { INetworkTransport } from './engine_networking_types.js';

/** Default transport that wraps the `websocket-ts` library */
export class WebsocketTransport implements INetworkTransport {
    private _url: string;
    private _ws: import('websocket-ts').Websocket | undefined;

    onOpen: (() => void) | null = null;
    onClose: (() => void) | null = null;
    onError: ((err: any) => void) | null = null;
    onMessage: ((data: string | Blob) => void) | null = null;

    get url() { return this._ws?.url ?? this._url; }

    constructor(url: string) {
        this._url = url;
    }

    async start() {
        const pkg = await import('websocket-ts');
        // @ts-ignore
        const WebsocketBuilder = pkg.default?.WebsocketBuilder ?? pkg.WebsocketBuilder;
        const ExponentialBackoff = pkg.default?.ExponentialBackoff ?? pkg.ExponentialBackoff;
        const ws = new WebsocketBuilder(this._url)
            .withMaxRetries(10)
            .withBackoff(new ExponentialBackoff(2000, 4))
            .onOpen(() => { this._ws = ws; this.onOpen?.(); })
            .onClose(() => { this.onClose?.(); })
            .onError(() => { this.onError?.(new Error("Websocket connection failed")); })
            .onRetry(() => { console.log("Retry connecting to networking websocket"); })
            .build();
        ws.addEventListener(pkg.WebsocketEvent.message, (_, msg) => {
            this.onMessage?.(msg.data);
        });
    }

    send(data: string | Uint8Array) {
        this._ws?.send(data);
    }

    close() {
        this._ws?.close();
        this._ws = undefined;
    }
}
