import {gallery_message} from "../protocol/gallery_messages";
import type {Json_Value} from "../protocol/gallery_types";

export interface Gallery_Socket_Events {on_json(raw: string): void; on_binary(buffer: ArrayBuffer): void; on_state(state: "connecting" | "ready" | "error" | "closed"): void;}
export function gallery_socket_url(location_value: Location = window.location): string {
    const query = new URLSearchParams(location_value.search);
    const hosted = location_value.protocol !== "file:" && ["/", "/index.html", "/gallery", "/gallery/"].includes(location_value.pathname);
    const preview = location_value.port === "63342";
    const port = query.get("port") || (hosted && !preview ? location_value.port : "8848") || "8848";
    const host = query.get("host") || (hosted ? location_value.hostname : "127.0.0.1") || "127.0.0.1";
    return `${location_value.protocol === "https:" ? "wss" : "ws"}://${host}:${port}/renderive/gallery`;
}
export class Gallery_Socket {
    private socket: WebSocket | null = null;
    constructor(private readonly url: string, private readonly events: Gallery_Socket_Events) {}
    connect(): void {
        if (this.socket && (this.socket.readyState === WebSocket.OPEN || this.socket.readyState === WebSocket.CONNECTING)) return;
        this.events.on_state("connecting");
        const socket = new WebSocket(this.url); this.socket = socket; socket.binaryType = "arraybuffer";
        socket.addEventListener("open", () => {if (this.socket === socket) this.events.on_state("ready");});
        socket.addEventListener("message", event => {if (this.socket !== socket) return; typeof event.data === "string" ? this.events.on_json(event.data) : event.data instanceof ArrayBuffer && this.events.on_binary(event.data);});
        socket.addEventListener("error", () => {if (this.socket === socket) this.events.on_state("error");});
        socket.addEventListener("close", () => {if (this.socket === socket) {this.socket = null; this.events.on_state("closed");}});
    }
    close(): void {const socket = this.socket; this.socket = null; socket?.close();}
    send(type: string, payload: Record<string, Json_Value> = {}): boolean {if (!this.socket || this.socket.readyState !== WebSocket.OPEN) return false; this.socket.send(gallery_message(type, payload)); return true;}
    buffered_bytes(): number {return this.socket?.bufferedAmount ?? 0;}
    is_open(): boolean {return this.socket?.readyState === WebSocket.OPEN;}
}
