"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var WebSocketClient_exports = {};
__export(WebSocketClient_exports, {
  WebSocketClient: () => WebSocketClient
});
module.exports = __toCommonJS(WebSocketClient_exports);
var import_Environmental = require("#environment/Environmental.js");
var import_MatterError = require("#MatterError.js");
var import_Promises = require("#util/Promises.js");
/**
 * @license
 * Copyright 2022-2026 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
class WebSocketClient {
  #Ctor;
  constructor(Ctor) {
    this.#Ctor = Ctor;
  }
  /**
   * Open a WebSocket connection and return it as a {@link HttpEndpoint.WsConnection}.
   */
  async connect(url) {
    const Ctor = this.#Ctor ?? globalThis.WebSocket;
    if (!Ctor) {
      throw new import_MatterError.NoProviderError("No WebSocket implementation available");
    }
    const ws = new Ctor(url);
    ws.binaryType = "arraybuffer";
    await new Promise((resolve, reject) => {
      ws.addEventListener("open", onOpen);
      ws.addEventListener("error", onError);
      function off() {
        ws.removeEventListener("open", onOpen);
        ws.removeEventListener("error", onError);
      }
      function onOpen() {
        off();
        resolve();
      }
      function onError() {
        off();
        reject(new Error(`WebSocket connection to ${url} failed`));
      }
    });
    return WebSocketClient.streams(ws);
  }
  static [import_Environmental.Environmental.create](env) {
    const instance = new WebSocketClient();
    env.set(WebSocketClient, instance);
    return instance;
  }
  /**
   * Wrap an open standard WebSocket into a {@link HttpEndpoint.WsConnection}.
   */
  static streams(ws) {
    return {
      readable: createReadable(ws),
      writable: createWritable(ws)
    };
  }
}
function createReadable(ws) {
  const queue = Array();
  const ready = new import_Promises.Gate();
  let isClosed = false;
  ws.addEventListener("message", onMessage);
  ws.addEventListener("error", onError);
  ws.addEventListener("close", onClose);
  return new ReadableStream({
    async pull(controller) {
      if (!isClosed && !queue.length) {
        await ready;
      }
      const next = queue.shift();
      if (!queue.length && !isClosed) {
        ready.close();
      }
      if (next === void 0) {
        controller.close();
        return;
      }
      if (next instanceof Error) {
        controller.error(next);
        return;
      }
      controller.enqueue(next);
    },
    cancel() {
      if (!isClosed) {
        ws.close();
        isClosed = true;
        queue.length = 0;
      }
    }
  });
  function onMessage(event) {
    let { data } = event;
    if (data instanceof ArrayBuffer) {
      data = new Uint8Array(data);
    }
    queue.push(data);
    ready.open();
  }
  function onError() {
    isClosed = true;
    queue.push(new Error("WebSocket error"));
    ready.open();
  }
  function onClose() {
    isClosed = true;
    ready.open();
  }
}
function createWritable(ws) {
  return new WritableStream({
    write(chunk) {
      ws.send(chunk);
    },
    close() {
      if (ws.readyState < 2) {
        ws.close(1e3);
      }
    },
    abort() {
      if (ws.readyState < 2) {
        ws.close();
      }
    }
  });
}
//# sourceMappingURL=WebSocketClient.js.map
