const _EventTarget = EventTarget;
const defaultOptions = Object.freeze({
  bidir: true,
  stream: true
});
class WebSocketSSE extends _EventTarget {
  static CONNECTING = 0;
  static OPEN = 1;
  static CLOSING = 2;
  static CLOSED = 3;
  CONNECTING = 0;
  OPEN = 1;
  CLOSING = 2;
  CLOSED = 3;
  /* eslint-disable unicorn/no-null */
  onclose = null;
  onerror = null;
  onopen = null;
  onmessage = null;
  /* eslint-enable unicorn/no-null */
  binaryType = "blob";
  readyState = WebSocketSSE.CONNECTING;
  url;
  protocol = "";
  extensions = "";
  bufferedAmount = 0;
  #options = {};
  #sse;
  #id;
  #sendController;
  #queue = [];
  constructor(url, init) {
    super();
    this.url = url.replace(/^ws/, "http");
    if (typeof init === "string") {
      this.#options = { ...defaultOptions, protocols: init };
    } else if (Array.isArray(init)) {
      this.#options = { ...defaultOptions, protocols: init };
    } else {
      this.#options = { ...defaultOptions, ...init };
    }
    this.#sse = new EventSource(this.url);
    this.#sse.addEventListener("open", (_sseEvent) => {
      this.readyState = WebSocketSSE.OPEN;
      const event = new Event("open");
      this.onopen?.(event);
      this.dispatchEvent(event);
    });
    this.#sse.addEventListener("message", (sseEvent) => {
      const _event = new MessageEvent("message", {
        data: sseEvent.data
      });
      this.onmessage?.(_event);
      this.dispatchEvent(_event);
    });
    if (this.#options.bidir) {
      this.#sse.addEventListener("crossws-id", (sseEvent) => {
        this.#id = sseEvent.data;
        if (this.#options.stream) {
          fetch(this.url, {
            method: "POST",
            // @ts-expect-error
            duplex: "half",
            headers: {
              "content-type": "application/octet-stream",
              "x-crossws-id": this.#id
            },
            body: new ReadableStream({
              start: (controller) => {
                this.#sendController = controller;
              },
              cancel: () => {
                this.#sendController = undefined;
              }
            }).pipeThrough(new TextEncoderStream())
          }).catch(() => {
          });
        }
        for (const data of this.#queue) {
          this.send(data);
        }
        this.#queue = [];
      });
    }
    this.#sse.addEventListener("error", (_sseEvent) => {
      const event = new Event("error");
      this.onerror?.(event);
      this.dispatchEvent(event);
    });
    this.#sse.addEventListener("close", (_sseEvent) => {
      this.readyState = WebSocketSSE.CLOSED;
      const event = new Event("close");
      this.onclose?.(event);
      this.dispatchEvent(event);
    });
  }
  close(_code, _reason) {
    this.readyState = WebSocketSSE.CLOSING;
    this.#sse.close();
    this.readyState = WebSocketSSE.CLOSED;
  }
  async send(data) {
    if (!this.#options.bidir) {
      throw new Error("bdir option is not enabled!");
    }
    if (this.readyState !== WebSocketSSE.OPEN) {
      throw new Error("WebSocket is not open!");
    }
    if (!this.#id) {
      this.#queue.push(data);
      return;
    }
    if (this.#sendController) {
      this.#sendController.enqueue(data);
      return;
    }
    await fetch(this.url, {
      method: "POST",
      headers: {
        "x-crossws-id": this.#id
      },
      body: data
    });
  }
}

export { WebSocketSSE };
