"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 BdxProtocol_exports = {};
__export(BdxProtocol_exports, {
  BdxProtocol: () => BdxProtocol
});
module.exports = __toCommonJS(BdxProtocol_exports);
var import_BdxError = require("#bdx/BdxError.js");
var import_FileDesignator = require("#bdx/FileDesignator.js");
var import_PersistedFileDesignator = require("#bdx/PersistedFileDesignator.js");
var import_general = require("#general");
var import_PeerAddress = require("#peer/PeerAddress.js");
var import_ExchangeManager = require("#protocol/ExchangeManager.js");
var import_SecureSession = require("#session/SecureSession.js");
var import_types = require("#types");
var import_BdxMessenger = require("./BdxMessenger.js");
var import_BdxSession = require("./BdxSession.js");
var import_BdxInitMessagesSchema = require("./schema/BdxInitMessagesSchema.js");
/**
 * @license
 * Copyright 2022-2026 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
const logger = import_general.Logger.get("BdxProtocol");
class BdxProtocol {
  id = import_types.BDX_PROTOCOL_ID;
  requiresSecureSession = true;
  #activeBdxSessions = /* @__PURE__ */ new Map();
  #peerScopes = /* @__PURE__ */ new Map();
  #sessionStarted = (0, import_general.Observable)();
  #sessionClosed = (0, import_general.Observable)();
  static [import_general.Environmental.create](env) {
    const instance = new BdxProtocol();
    env.get(import_ExchangeManager.ExchangeManager).addProtocolHandler(instance);
    env.set(BdxProtocol, instance);
    return instance;
  }
  get sessionStarted() {
    return this.#sessionStarted;
  }
  get sessionClosed() {
    return this.#sessionClosed;
  }
  #peerScopeKey(peer, scope) {
    if (scope === void 0) {
      throw new import_general.MatterError("StorageContext must have a defined scope to be used with enableScope");
    }
    return `${peer.toString()}-${scope}`;
  }
  enablePeerForScope(peer, storage, config) {
    const peerScopeStr = this.#peerScopeKey(peer, storage.scope);
    const peerDetails = this.#peerScopes.get(peerScopeStr);
    if (peerDetails !== void 0) {
      const { storage: existingStorage, config: existingConfig } = peerDetails;
      if (existingStorage !== storage || !(0, import_general.isDeepEqual)(config, existingConfig)) {
        logger.warn(
          "Cannot enable BDX for peer",
          peer,
          "with different storage or config:",
          config,
          "vs",
          existingConfig
        );
        return false;
      }
    } else {
      this.#peerScopes.set(peerScopeStr, { peer, storage, config });
    }
    return true;
  }
  async disablePeerForScope(peer, storage, force = false) {
    if (this.#activeBdxSessions.size > 0) {
      for (const { session, scope } of this.#activeBdxSessions.values()) {
        if (storage.scope === scope && import_PeerAddress.PeerAddress.is(peer, session.peerAddress)) {
          if (force) {
            await session.close(new import_general.MatterError("BDX protocol scope disabled"));
            break;
          }
          throw new import_general.MatterError(
            `Cannot disable BDX for peer "${peer}" (scope: ${scope}) because there are active BDX sessions using it`
          );
        }
      }
    }
    this.#peerScopes.delete(this.#peerScopeKey(peer, storage.scope));
  }
  async onNewExchange(exchange, message) {
    const initMessageType = message.payloadHeader.messageType;
    import_SecureSession.SecureSession.assert(exchange.session);
    switch (initMessageType) {
      case import_types.BdxMessageType.SendInit:
      case import_types.BdxMessageType.ReceiveInit:
        let messenger = void 0;
        try {
          logger.debug(
            `Initialize Session for ${import_types.BdxMessageType[initMessageType]} message on BDX protocol for exchange ${exchange.id}`
          );
          await exchange.nextMessage();
          const { payload } = message;
          const initMessage = new import_BdxInitMessagesSchema.BdxInitMessageSchema().decode(payload);
          const { fileDesignator: messageFileDesignator } = initMessage;
          const fd = new import_FileDesignator.FileDesignator(messageFileDesignator);
          const [storageScope, fileDesignator] = fd.text.split("/");
          const { storage, config } = this.#peerScopes.get(this.#peerScopeKey(exchange.session.peerAddress, storageScope)) ?? {};
          if (storage === void 0 || fileDesignator === void 0) {
            throw new import_BdxError.BdxError(
              `No storage context found for BDX file designator "${fd.text}"`,
              import_types.BdxStatusCode.FileDesignatorUnknown
            );
          }
          messenger = new import_BdxMessenger.BdxMessenger(exchange, config?.messageTimeout);
          const bdxSession = import_BdxSession.BdxSession.fromMessage(messenger, {
            initMessageType,
            initMessage,
            fileDesignator: new import_PersistedFileDesignator.PersistedFileDesignator(fileDesignator, storage),
            ...config
          });
          await this.#registerSession(messenger, bdxSession, storageScope);
          try {
            await bdxSession.processTransfer();
          } catch (error) {
            logger.error(`Error processing BDX transfer:`, error);
          }
        } catch (error) {
          import_BdxError.BdxError.accept(error);
          await (messenger ?? new import_BdxMessenger.BdxMessenger(exchange)).sendError(error.code);
          logger.warn(`BDX session failed with error:`, error);
          return;
        }
        break;
      default:
        logger.warn(
          `Unexpected BDX message type ${import_types.BdxMessageType[initMessageType]} on new exchange ${exchange.id}`
        );
        await new import_BdxMessenger.BdxMessenger(exchange).sendError(import_types.BdxStatusCode.UnexpectedMessage);
    }
  }
  /** Make sure only one BDX session can be active per exchange and that the exchange is closed with the BDX session. */
  async #registerSession(messenger, bdxSession, scope) {
    const exchange = messenger.exchange;
    if (this.#activeBdxSessions.has(exchange)) {
      logger.warn(`BDX session for exchange ${exchange.id} already exists, sending error`);
      await messenger.sendError(import_types.BdxStatusCode.UnexpectedMessage);
      return;
    }
    this.#activeBdxSessions.set(exchange, { session: bdxSession, scope });
    this.#sessionStarted.emit(bdxSession, scope);
    bdxSession.closed.on(async () => {
      logger.debug(`BDX session for exchange ${exchange.id} closed`);
      this.#activeBdxSessions.delete(exchange);
      await exchange.close();
      this.#sessionClosed.emit(bdxSession, scope);
    });
  }
  async close() {
    logger.debug(`Closing BDX protocol handler with ${this.#activeBdxSessions.size} active sessions`);
    for (const { session } of this.#activeBdxSessions.values()) {
      await session.close(new import_general.MatterError("BDX protocol handler closed"));
    }
    this.#activeBdxSessions.clear();
  }
  sessionFor(peerAddress, scope) {
    for (const { session, scope: activeScope } of this.#activeBdxSessions.values()) {
      if (import_PeerAddress.PeerAddress.is(peerAddress, session.peerAddress) && activeScope === scope) {
        return session;
      }
    }
    return void 0;
  }
}
//# sourceMappingURL=BdxProtocol.js.map
