"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 WebSocketConnection_exports = {};
__export(WebSocketConnection_exports, {
  WebSocketConnection: () => WebSocketConnection
});
module.exports = __toCommonJS(WebSocketConnection_exports);
var import_general = require("@matter/general");
/**
 * @license
 * Copyright 2022-2026 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
const logger = import_general.Logger.get("WebSocketConnection");
class WebSocketConnection {
  #ws;
  #url;
  #env;
  #abort = new import_general.Abort();
  #nextId = 1;
  #pending = /* @__PURE__ */ new Map();
  #subscriptionListeners = /* @__PURE__ */ new Map();
  #readLoop;
  constructor(url, env) {
    this.#url = url;
    this.#env = env;
  }
  get url() {
    return this.#url;
  }
  /**
   * Open the WebSocket connection and start the read loop.
   */
  async open() {
    this.#ws = await this.#env.get(import_general.WebSocketClient).connect(this.#url);
    this.#readLoop = this.#runReadLoop();
  }
  /**
   * Close the connection.
   */
  async close() {
    this.#abort();
    for (const pending of this.#pending.values()) {
      pending.reject(new Error("Connection closed"));
    }
    this.#pending.clear();
    this.#subscriptionListeners.clear();
    await this.#readLoop;
    this.#ws = void 0;
  }
  /**
   * Send a request and wait for a single response.
   */
  async request(request) {
    const id = String(this.#nextId++);
    const message = { ...request, id };
    return new Promise((resolve, reject) => {
      this.#pending.set(id, { resolve, reject });
      this.#send(message).catch(reject);
    });
  }
  /**
   * Send a subscribe request.  Returns the subscription ID and installs a listener for streaming responses.
   *
   * The caller receives the "ok" confirmation, then subsequent update/delete responses arrive via the listener.
   */
  async subscribe(request, listener) {
    const id = String(this.#nextId++);
    const message = { ...request, id };
    return new Promise((resolve, reject) => {
      this.#pending.set(id, {
        resolve: (response) => {
          if (response.kind === "ok") {
            this.#subscriptionListeners.set(id, listener);
          }
          resolve(response);
        },
        reject
      });
      this.#send(message).catch(reject);
    });
  }
  /**
   * Remove a subscription listener.
   */
  unsubscribe(id) {
    this.#subscriptionListeners.delete(id);
  }
  async #send(message) {
    if (!this.#ws) {
      throw new Error("WebSocket not connected");
    }
    const writer = this.#ws.writable.getWriter();
    try {
      await writer.write((0, import_general.asJson)(message));
    } finally {
      writer.releaseLock();
    }
  }
  async #runReadLoop() {
    if (!this.#ws) {
      return;
    }
    try {
      for await (let message of import_general.Stream.iterable(this.#ws.readable)) {
        if (import_general.Abort.is(this.#abort)) {
          break;
        }
        try {
          const text = typeof message === "string" ? message : import_general.Bytes.toString(message);
          const response = JSON.parse(text);
          this.#dispatch(response);
        } catch (e) {
          logger.error("Error processing WebSocket message:", e);
        }
      }
    } catch (e) {
      if (!import_general.Abort.is(this.#abort)) {
        logger.error("WebSocket read loop error:", e);
      }
    }
  }
  #dispatch(response) {
    const id = response.id;
    if (id !== void 0) {
      const subscriptionListener = this.#subscriptionListeners.get(id);
      if (subscriptionListener) {
        subscriptionListener(response);
        return;
      }
      const pending = this.#pending.get(id);
      if (pending) {
        this.#pending.delete(id);
        if (response.kind === "error") {
          pending.reject(new Error(response.message));
        } else {
          pending.resolve(response);
        }
        return;
      }
    }
    logger.debug("Received unmatched response:", response.kind, id ?? "(no id)");
  }
}
//# sourceMappingURL=WebSocketConnection.js.map
