"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
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 __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  // If the importer is in node compatibility mode or this is not an ESM
  // file that has been converted to a CommonJS file using a Babel-
  // compatible transform (i.e. "__esModule" has not been set), then set
  // "default" to the CommonJS "module.exports" for node compatibility.
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var container_exports = {};
__export(container_exports, {
  Container: () => Container
});
module.exports = __toCommonJS(container_exports);
var import_dockerode = __toESM(require("dockerode"), 1);
var import_promises = require("node:stream/promises");
var import_text = require("../util/text.js");
var import_errors = require("./errors.js");
var import_image = require("./image.js");
var import_terminal = require("./terminal.js");
/**
 * @license
 * Copyright 2022-2026 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
function Container(docker, input) {
  if (input instanceof import_dockerode.default.Container) {
    return adaptContainer(docker, input);
  }
  return createContainer(docker, input);
}
async function createContainer(docker, config) {
  const dockerodeConfig = configureContainer(config);
  const ct = await import_errors.DockerError.adapt(docker.intf.createContainer(dockerodeConfig));
  return adaptContainer(docker, ct);
}
function configureContainer(options) {
  const createOptions = {
    Image: options.image,
    HostConfig: {
      AutoRemove: options?.autoRemove,
      // Ugh.  With a proper networking config we can perhaps avoid this.  Probably makes sense to run a utility
      // container with avahi
      SecurityOpt: ["apparmor:unconfined"]
    },
    AttachStdout: true,
    AttachStderr: true
  };
  const { name, entrypoint, env, binds, command, openStdin, network, cwd, platform } = options ?? {};
  if (typeof network === "string") {
    createOptions.HostConfig.NetworkMode = network;
  } else if (network) {
    const networks = Array.isArray(network) ? network : [network];
    createOptions.NetworkingConfig = {
      EndpointsConfig: Object.fromEntries(networks.map((n) => [n.name, {}]))
    };
  }
  if (cwd !== void 0) {
    createOptions.WorkingDir = cwd;
  }
  if (name !== void 0) {
    createOptions.name = name;
  }
  if (entrypoint !== void 0) {
    createOptions.Entrypoint = entrypoint;
  }
  if (env) {
    createOptions.Env = Object.entries(env).map(([k, v]) => `${k}=${v}`);
  }
  if (binds) {
    createOptions.HostConfig.Binds = Object.entries(binds).map(([k, v]) => `${k}:${v}`);
  }
  if (command) {
    createOptions.Cmd = Array.isArray(command) ? command : [command];
  }
  if (openStdin !== false) {
    createOptions.OpenStdin = true;
    createOptions.AttachStdin = true;
    createOptions.StdinOnce = true;
  }
  if (platform) {
    createOptions.platform = platform;
  }
  return createOptions;
}
function adaptContainer(docker, ct) {
  return {
    docker,
    get image() {
      return import_errors.DockerError.adapt(ct.inspect().then((info) => (0, import_image.Image)(docker, info.Image)));
    },
    async start() {
      await import_errors.DockerError.adapt(ct.start());
    },
    async kill() {
      await import_errors.DockerError.adapt(ct.kill());
    },
    async remove(force) {
      await import_errors.DockerError.adapt(ct.remove({ force }));
    },
    async attach(terminal, stdin = false) {
      const exited = new Promise((resolve, reject) => {
        this.wait().then(resolve, reject);
      });
      return terminal(
        this.docker,
        await import_errors.DockerError.adapt(ct.attach({ stream: true, stdin, stdout: true, stderr: true })),
        exited
      );
    },
    async exec(command, terminalOrOptions, options) {
      let terminal;
      if (typeof terminalOrOptions === "object") {
        options = terminalOrOptions;
      } else {
        terminal = terminalOrOptions;
      }
      const { stdin, cwd, env } = options ?? {};
      if (!Array.isArray(command)) {
        command = [command];
      }
      const config = {
        Cmd: command,
        AttachStdin: stdin,
        AttachStdout: true,
        AttachStderr: true
      };
      if (cwd !== void 0) {
        config.WorkingDir = cwd;
      }
      if (env !== void 0) {
        config.Env = Object.entries(env).map(([k, v]) => `${k}=${v}`);
      }
      const exec = await import_errors.DockerError.adapt(ct.exec(config));
      const stream = await import_errors.DockerError.adapt(exec.start({ hijack: true, stdin }));
      const exited = new Promise((resolve, reject) => {
        (0, import_promises.finished)(stream).then(() => {
          exec.inspect().then((info) => {
            if (info.ExitCode) {
              reject(new import_errors.NonZeroExitError(info.ExitCode));
            } else {
              resolve();
            }
          }, reject);
        }, reject);
      });
      if (terminal === void 0) {
        const term = import_terminal.Terminal.Raw(docker, stream, exited);
        await term.consume();
        return;
      }
      return terminal(this.docker, stream, exited);
    },
    async wait(options) {
      const code = (await import_errors.DockerError.adapt(ct.wait(options))).StatusCode;
      if (code) {
        throw new import_errors.NonZeroExitError(code);
      }
    },
    async read(path, terminal) {
      const term = await this.exec(["cat", path], terminal ?? import_terminal.Terminal.Line);
      if (terminal === void 0) {
        return await term.consume();
      }
      return term;
    },
    async follow(path, terminal) {
      return this.exec(["tail", "--follow=name", path], terminal ?? import_terminal.Terminal.StdoutLine);
    },
    async execAndRead(command, terminal) {
      const term = await this.exec(command, terminal ?? import_terminal.Terminal.Line);
      if (terminal === void 0) {
        return await term.consume();
      }
      return term;
    },
    async write(path, contents) {
      const terminal = await this.exec(["bash", "-c", `cat - > ${shesc(path)}`], import_terminal.Terminal.Raw, { stdin: true });
      await terminal.write(contents);
      await terminal.close();
    },
    edit(editor, ...paths) {
      return editor(this, paths);
    },
    async delete(path, options) {
      const command = ["rm"];
      if (options?.recursive) {
        command.push("-r");
      }
      if (options?.force) {
        command.push("-f");
      }
      command.push(path);
      await this.exec(command);
    },
    async resolveGlob(glob) {
      const terminal = await this.exec(["bash", "-c", `ls ${glob}`], import_terminal.Terminal.Line);
      const output = await terminal.consume();
      return output.split("\n").filter((line) => line !== "");
    },
    async createPipe(name) {
      await this.exec(["rm", "-f", name]);
      await this.exec(["mkfifo", name]);
    }
  };
}
function shesc(value) {
  return `"$(echo ${(0, import_text.base64Of)(value)} | base64 -d)"`;
}
//# sourceMappingURL=container.js.map
