"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 OutboundFlow_exports = {};
__export(OutboundFlow_exports, {
  OutboundFlow: () => OutboundFlow
});
module.exports = __toCommonJS(OutboundFlow_exports);
var import_general = require("@matter/general");
var import_types = require("@matter/types");
var import_BdxError = require("../BdxError.js");
var import_Flow = require("./Flow.js");
/**
 * @license
 * Copyright 2022-2026 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
class OutboundFlow extends import_Flow.Flow {
  #closeStreams;
  #iterator;
  #streamReader;
  get stream() {
    if (this.#iterator === void 0 || this.#streamReader === void 0) {
      throw new import_general.InternalError("Read stream not initialized");
    }
    return { iterator: this.#iterator, streamReader: this.#streamReader };
  }
  /**
   * Returns initialized streams for the transfer and initializes the #closeStream class function
   */
  async initTransfer() {
    const { blockSize } = this.transferParameters;
    const blob = await this.transferParameters.fileDesignator.openBlob();
    const blobSize = blob.size;
    const { startOffset = 0, dataLength = blobSize } = this.transferParameters;
    this.dataLength = dataLength;
    const dataBlob = startOffset > 0 || dataLength !== blobSize ? blob.slice(startOffset, startOffset + dataLength) : blob;
    const stream = dataBlob.stream();
    const reader = stream.getReader();
    this.#closeStreams = async (_error) => {
      if (stream.locked) {
        reader?.releaseLock();
        try {
          await reader?.cancel();
        } catch (error) {
          if (!(error instanceof TypeError)) {
            throw error;
          }
        }
      }
      await stream.cancel();
    };
    const streamReader = new import_general.BytesStreamReader(reader);
    this.#iterator = streamReader.read(blockSize);
    this.#streamReader = streamReader;
  }
  /**
   * Reads one data chunk from the reader and does some basic checks.
   */
  async readDataChunk(reader) {
    const { blockSize, dataLength } = this.transferParameters;
    let { value, done = false } = await reader.next();
    if (value === void 0) {
      if (!done) {
        throw new import_BdxError.BdxError(
          `Data length too short, expected ${blockSize}bytes, but got less`,
          import_types.BdxStatusCode.LengthTooShort
        );
      }
      value = new Uint8Array();
    } else if (value.byteLength < blockSize) {
      ({ done = false } = await reader.next());
      if (!done) {
        throw new import_BdxError.BdxError(
          `Data length too short, expected ${blockSize}bytes, but got less`,
          import_types.BdxStatusCode.LengthTooShort
        );
      }
    }
    if (this.bytesLeft !== void 0 && dataLength !== void 0) {
      this.bytesLeft -= value.byteLength;
      if (this.bytesLeft < 0) {
        throw new import_BdxError.BdxError(
          `Data length exceeded, expected ${dataLength}bytes, but got ${-this.bytesLeft}bytes more`,
          import_types.BdxStatusCode.LengthTooLarge
        );
      }
      if (done && this.bytesLeft > 0) {
        throw new import_BdxError.BdxError(
          `Data length too short, expected ${dataLength}bytes, but got ${this.bytesLeft}bytes less`,
          import_types.BdxStatusCode.LengthTooShort
        );
      }
      if (this.bytesLeft === 0) {
        done = true;
      }
    }
    return { data: value, done };
  }
  async finalizeTransfer() {
    const blockCounter = this.finalBlockCounter;
    const { blockCounter: ackedBlockCounter } = await this.messenger.readBlockAckEof();
    this.validateCounter(ackedBlockCounter, blockCounter);
  }
  async close(error) {
    await super.close(error);
    await this.#closeStreams?.(error);
  }
}
//# sourceMappingURL=OutboundFlow.js.map
