"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 BdxSession_exports = {};
__export(BdxSession_exports, {
  BdxSession: () => BdxSession
});
module.exports = __toCommonJS(BdxSession_exports);
var import_general = require("#general");
var import_SecureSession = require("#session/SecureSession.js");
var import_types = require("#types");
var import_bdx_session_initiator = require("./bdx-session-initiator.js");
var import_BdxError = require("./BdxError.js");
var import_BdxSessionConfiguration = require("./BdxSessionConfiguration.js");
var import_DrivenSendingFlow = require("./flow/DrivenSendingFlow.js");
var import_DrivingReceivingFlow = require("./flow/DrivingReceivingFlow.js");
var import_Flow = require("./flow/Flow.js");
var import_FollowingReceivingFlow = require("./flow/FollowingReceivingFlow.js");
var import_FollowingSendingFlow = require("./flow/FollowingSendingFlow.js");
/**
 * @license
 * Copyright 2022-2026 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
const logger = import_general.Logger.get("BdxSession");
class BdxSession {
  #messenger;
  #started = false;
  #closed = (0, import_general.AsyncObservable)();
  #isClosed = false;
  #config;
  #transferFlow;
  #progressInfo = (0, import_general.Observable)();
  #progressFinished = (0, import_general.Observable)();
  #progressCancelled = (0, import_general.Observable)();
  /** Initializes a BdxSession as a sender, means that we upload data to the peer. */
  static asSender(messenger, options) {
    return new BdxSession(messenger, { isSender: true, ...options });
  }
  /** Initializes a BdxSession as a receiver, means that we download data from the peer. */
  static asReceiver(messenger, options) {
    return new BdxSession(messenger, { isSender: false, ...options });
  }
  /**
   * Initializes a BdxSession from an incoming *Init message. The message determines the direction of the transfer.
   * The provided storages allow to map the file designator to a storage context depending on the path prefix in the
   * file designator.
   */
  static fromMessage(messenger, options) {
    const { initMessageType } = options;
    if (initMessageType !== import_types.BdxMessageType.SendInit && initMessageType !== import_types.BdxMessageType.ReceiveInit) {
      throw new import_BdxError.BdxError(
        `Invalid message type for BDX session initialization: ${import_types.BdxMessageType[initMessageType]} (${initMessageType})`,
        import_types.BdxStatusCode.UnexpectedMessage
      );
    }
    return new BdxSession(messenger, {
      isSender: initMessageType === import_types.BdxMessageType.ReceiveInit,
      ...options
    });
  }
  constructor(messenger, options) {
    this.#messenger = messenger;
    this.#config = new import_BdxSessionConfiguration.BdxSessionConfiguration(options);
    const exchange = messenger.exchange;
    if (!exchange.session.isSecure) {
      throw new import_BdxError.BdxError("Bdx Protocol requires a secure session.");
    }
    exchange.closed.on(async () => {
      if (this.#isClosed) {
        return;
      }
      logger.debug(`Closing BDX session for exchange ${exchange.id}`);
      await this.close();
    });
  }
  get progressInfo() {
    return this.#progressInfo;
  }
  get progressFinished() {
    return this.#progressFinished;
  }
  get progressCancelled() {
    return this.#progressCancelled;
  }
  /** Method called to start the session. It will end with a successful Transfer or with an error */
  async processTransfer() {
    if (this.#started) {
      throw new import_BdxError.BdxError("BDX session already started", import_types.BdxStatusCode.UnexpectedMessage);
    }
    if (this.#isClosed) {
      throw new import_BdxError.BdxError("BDX session already closed", import_types.BdxStatusCode.UnexpectedMessage);
    }
    const { isSender, isInitiator, fileDesignator } = this.#config;
    logger.info(
      `Starting BDX session`,
      import_general.Diagnostic.dict({
        exId: this.#messenger.exchange.id,
        isSender,
        isInitiator,
        blobName: fileDesignator?.text
      })
    );
    this.#started = true;
    try {
      this.#transferFlow = this.#initializeFlow(await (0, import_bdx_session_initiator.bdxSessionInitiator)(this.#messenger, this.#config));
      this.#transferFlow.progressInfo.on(
        (bytesTransferred, totalBytesLength) => this.#progressInfo.emit(bytesTransferred, totalBytesLength)
      );
      this.#transferFlow.progressFinished.on(
        (totalBytesTransferred) => this.#progressFinished.emit(totalBytesTransferred)
      );
      this.#transferFlow.progressCancelled.on(() => this.#progressCancelled.emit());
      await this.#transferFlow.processTransfer();
      await this.close();
    } catch (error) {
      import_BdxError.BdxError.accept(error);
      await this.#messenger.sendError(error.code);
      logger.warn(`BDX session failed with error:`, error);
      await this.close(error);
      error.bytesTransferred = this.#transferFlow?.transferredBytes ?? 0;
      error.totalBytesLength = this.#transferFlow?.dataLength;
      throw error;
    }
  }
  #initializeFlow(transferParameters) {
    const { transferMode, asynchronousTransfer, dataLength, isDriver, fileDesignator } = transferParameters;
    const isSenderDrive = transferMode === import_Flow.Flow.DriverMode.SenderDrive;
    const role = `${isSenderDrive ? `${asynchronousTransfer ? "async " : ""}sending` : "receiving"} ${isDriver ? "driver" : "follower"}`;
    logger.debug(
      `Starting transfer flow as ${role}`,
      import_general.Diagnostic.dict({
        exId: this.#messenger.exchange.id,
        dataLength,
        blobName: fileDesignator.text
      })
    );
    let FlowImpl;
    if (isDriver) {
      if (isSenderDrive || asynchronousTransfer) {
        FlowImpl = import_DrivenSendingFlow.DrivenSendingFlow;
      } else {
        FlowImpl = import_DrivingReceivingFlow.DrivingReceivingFlow;
      }
    } else if (isSenderDrive || asynchronousTransfer) {
      FlowImpl = import_FollowingSendingFlow.FollowingSendingFlow;
    } else {
      FlowImpl = import_FollowingReceivingFlow.FollowingReceivingFlow;
    }
    return new FlowImpl(this.#messenger, transferParameters);
  }
  get closed() {
    return this.#closed;
  }
  get peerAddress() {
    import_SecureSession.SecureSession.assert(this.#messenger.exchange.session);
    return this.#messenger.exchange.session.peerAddress;
  }
  async close(error) {
    if (this.#isClosed) {
      return;
    }
    this.#isClosed = true;
    await this.#transferFlow?.close(error);
    await this.#closed.emit();
  }
}
//# sourceMappingURL=BdxSession.js.map
