"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = _default;
exports.pullImages = pullImages;
exports.runImage = runImage;
var _cluster = _interopRequireDefault(require("cluster"));
var _types = require("../types");
var _messages = require("./messages");
var _utils = require("./utils");
var _dockerode = _interopRequireDefault(require("dockerode"));
var _stream = require("stream");
var _ora = _interopRequireDefault(require("ora"));
var _logger = require("./logger");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
const docker = new _dockerode.default();
class DevNull extends _stream.Writable {
  _write(_chunk, _encoding, callback) {
    setImmediate(callback);
  }
}
async function pullImages(images, {
  auth,
  platform
} = {}) {
  const args = {};
  if (auth) args.authconfig = auth;
  if (platform) args.platform = platform;
  _logger.logger.info('Pull docker images');
  for (const image of images) {
    await new Promise((resolve, reject) => {
      const spinner = (0, _ora.default)(`${image}: Pull start`).start();

      // eslint-disable-next-line @typescript-eslint/no-floating-promises
      docker.pull(image, args, function (pullError, stream) {
        if (pullError) {
          spinner.fail();
          return reject(pullError);
        }

        // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
        docker.modem.followProgress(stream, onFinished, onProgress);
        function onFinished(error) {
          if (error) {
            spinner.fail();
            return reject(error);
          }
          spinner.succeed(`${image}: Pull complete`);
          resolve();
        }
        function onProgress(event) {
          if (!/^[a-z0-9]{12}$/i.test(event.id)) return;
          spinner.text = `${image}: [${event.id}] ${event.status} ${event.progress ? `${event.progress}` : ''}`;
        }
      });
    });
  }
}
async function runImage(image, args, options, debug) {
  await Promise.all((await docker.listContainers({
    all: true,
    filters: {
      ancestor: [image]
    }
  })).map(async info => {
    const container = docker.getContainer(info.Id);
    try {
      await container.stop();
    } catch (_) {
      /* noop */
    }
    await container.remove();
  }));
  const hub = docker.run(image, args, debug ? process.stdout : new DevNull(), options, error => {
    if (error) throw error;
  });
  return new Promise(resolve => {
    hub.once('container', container => {
      // eslint-disable-next-line @typescript-eslint/no-misused-promises
      (0, _messages.subscribeOn)('shutdown', async () => {
        try {
          await container.stop();
          await container.remove();
        } catch (error) {
          /* noop */
        }
      });
    });
    hub.once('start', container => void container.inspect().then(info => resolve(info.NetworkSettings.Networks.bridge.IPAddress)));
  });
}
async function _default(config, browser, startContainer) {
  if (_cluster.default.isPrimary) {
    const host = await startContainer();
    let gridUrl = 'http://localhost:4444/wd/hub';
    gridUrl = _utils.isInsideDocker ? gridUrl.replace(_utils.LOCALHOST_REGEXP, host) : gridUrl;
    _cluster.default.on('message', (worker, message) => {
      if (!(0, _types.isDockerMessage)(message)) return;
      const dockerMessage = message;
      if (dockerMessage.type != 'start') return;
      (0, _messages.sendDockerMessage)(worker, {
        type: 'success',
        payload: {
          gridUrl
        }
      });
    });
  } else {
    if (browser && config.browsers[browser].gridUrl) return Promise.resolve();
    return new Promise(resolve => {
      (0, _messages.subscribeOn)('docker', message => {
        if (message.type == 'success') {
          config.gridUrl = message.payload.gridUrl;
          resolve();
        }
      });
      (0, _messages.emitDockerMessage)({
        type: 'start'
      });
    });
  }
}