/**
 * @license
 * Copyright 2022-2026 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
import { promisify } from "node:util";
import { asyncLinesOf, textOf } from "../util/text.js";
import { NonZeroExitError } from "./errors.js";
var Terminal;
((Terminal2) => {
  function Raw(docker, stream, exited) {
    const buffer = Array();
    let closed = false;
    let signalReadReady;
    let readReady;
    resetBuffer();
    stream.on("close", () => {
      closed = true;
      signalReadReady();
    });
    const stdout = createOutputStream("stdout");
    const stderr = createOutputStream("stderr");
    docker.intf.modem.demuxStream(stream, stdout, stderr);
    const write = promisify(stream.write).bind(stream);
    exited.catch(() => {
    });
    return {
      async write(content) {
        if (content === void 0 || content === null) {
          return;
        }
        if (typeof content === "object" && Symbol.asyncIterator in content) {
          for await (const chunk of content) {
            await this.write(chunk);
          }
        } else if (typeof content === "string" || content instanceof Uint8Array) {
          await write(content);
        } else if (ArrayBuffer.isView(content)) {
          await write(new Uint8Array(content.buffer, content.byteOffset, content.byteLength));
        } else if (typeof content === "object" && Symbol.iterator in content) {
          for (const chunk of content) {
            await this.write(chunk);
          }
        } else {
          await write(content.toString());
        }
      },
      async close() {
        if (closed) {
          return;
        }
        await promisify(stream.end).bind(stream)();
        if ("destroy" in stream && typeof stream.destroy === "function") {
          stream.destroy();
        }
      },
      async consume() {
        const chunks = Array();
        let length = 0;
        try {
          for await (const chunk of this) {
            chunks.push(chunk);
            length += chunk.length;
          }
        } catch (e) {
          if (e instanceof NonZeroExitError) {
            let message = textOf(join());
            if (message.length > 256) {
              message = message.slice(0, 256) + "\u2026";
            }
            e = new NonZeroExitError(e.code, message);
          }
          throw e;
        }
        return join();
        function join() {
          const output = new Uint8Array(length);
          let pos = 0;
          for (const chunk of chunks) {
            output.set(chunk, pos);
            pos += chunk.length;
          }
          return output;
        }
      },
      [Symbol.asyncIterator]: function() {
        return {
          async next() {
            while (!closed || buffer.length) {
              await readReady;
              let result;
              if (buffer.length) {
                result = {
                  done: false,
                  value: buffer.shift()
                };
                if (!buffer.length && !closed) {
                  resetBuffer();
                }
                return result;
              }
              if (!closed) {
                resetBuffer();
              }
            }
            await exited;
            return {
              done: true,
              value: void 0
            };
          }
        };
      }
    };
    function resetBuffer() {
      readReady = new Promise((resolve) => {
        signalReadReady = resolve;
      });
    }
    function createOutputStream(source) {
      return {
        write(chunk) {
          if (!(chunk instanceof Uint8Array)) {
            throw new Error("Input chunk is not a byte array");
          }
          chunk.source = source;
          buffer.push(chunk);
          signalReadReady();
        }
      };
    }
  }
  Terminal2.Raw = Raw;
  function Line(docker, stream, exited) {
    const raw = Raw(docker, stream, exited);
    return createLineTerminal(raw);
  }
  Terminal2.Line = Line;
  function StdoutLine(docker, stream, exited) {
    const raw = Raw(docker, stream, exited);
    return createLineTerminal(raw, (chunk) => chunk.source === "stdout" ? chunk : void 0);
  }
  Terminal2.StdoutLine = StdoutLine;
})(Terminal || (Terminal = {}));
function createLineTerminal(raw, filter) {
  return {
    write(content) {
      return raw.write(content);
    },
    close() {
      return raw.close();
    },
    consume() {
      return raw.consume().then(textOf);
    },
    [Symbol.asyncIterator]() {
      return asyncLinesOf(raw, filter);
    }
  };
}
export {
  Terminal
};
//# sourceMappingURL=terminal.js.map
