"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.startSelenoidContainer = startSelenoidContainer;
exports.startSelenoidStandalone = startSelenoidStandalone;
var _path = _interopRequireDefault(require("path"));
var _util = require("util");
var _fs = require("fs");
var _utils = require("../utils");
var _docker = require("../docker");
var _core = require("@octokit/core");
var _messages = require("../messages");
var _cluster = _interopRequireDefault(require("cluster"));
var _shelljs = require("shelljs");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
const mkdirAsync = (0, _util.promisify)(_fs.mkdir);
const writeFileAsync = (0, _util.promisify)(_fs.writeFile);
const copyFileAsync = (0, _util.promisify)(_fs.copyFile);
async function createSelenoidConfig(browsers, {
  useDocker
}) {
  const selenoidConfig = {};
  const selenoidConfigDir = _path.default.join((0, _utils.getCreeveyCache)(), 'selenoid');
  browsers.forEach(({
    browserName,
    version = 'latest',
    browserVersion = version,
    dockerImage = `selenoid/${browserName}:${browserVersion}`,
    webdriverCommand = []
  }) => {
    if (!selenoidConfig[browserName]) selenoidConfig[browserName] = {
      default: browserVersion,
      versions: {}
    };
    if (!useDocker && webdriverCommand.length == 0) throw new Error('Please specify "webdriverCommand" browser option with path to browser webdriver');
    selenoidConfig[browserName].versions[browserVersion] = {
      image: useDocker ? dockerImage : webdriverCommand,
      port: '4444',
      path: !useDocker || ['chrome', 'opera', 'webkit', 'MicrosoftEdge'].includes(browserName) ? '/' : '/wd/hub'
    };
  });
  await mkdirAsync(selenoidConfigDir, {
    recursive: true
  });
  await writeFileAsync(_path.default.join(selenoidConfigDir, 'browsers.json'), JSON.stringify(selenoidConfig));
  return selenoidConfigDir;
}
async function downloadSelenoidBinary(destination) {
  const platformNameMapping = {
    darwin: 'selenoid_darwin_amd64',
    linux: 'selenoid_linux_amd64',
    win32: 'selenoid_windows_amd64.exe'
  };
  const octokit = new _core.Octokit();
  const response = await octokit.request('GET /repos/{owner}/{repo}/releases/latest', {
    owner: 'aerokube',
    repo: 'selenoid'
  });
  const {
    assets
  } = response.data;
  const {
    browser_download_url: downloadUrl,
    size: binarySize
  } = assets.find(({
    name
  }) => platformNameMapping[process.platform] == name) ?? {};
  if ((0, _fs.existsSync)(destination) && (0, _fs.lstatSync)(destination).size == binarySize) return;
  if (!downloadUrl) {
    throw new Error(`Couldn't get download url for selenoid binary. Please download it manually from "https://github.com/aerokube/selenoid/releases/latest" and define "selenoidPath" option in the Creevey config`);
  }
  return (0, _utils.downloadBinary)(downloadUrl, destination);
}
async function startSelenoidStandalone(config, debug) {
  config.gridUrl = 'http://localhost:4444/wd/hub';
  if (_cluster.default.isWorker) return;
  const browsers = Object.values(config.browsers).filter(browser => !browser.gridUrl);
  const selenoidConfigDir = await createSelenoidConfig(browsers, {
    useDocker: false
  });
  const binaryPath = _path.default.join(selenoidConfigDir, process.platform == 'win32' ? 'selenoid.exe' : 'selenoid');
  if (config.selenoidPath) {
    await copyFileAsync(_path.default.resolve(config.selenoidPath), binaryPath);
  } else {
    await downloadSelenoidBinary(binaryPath);
  }

  // TODO Download browser webdrivers
  try {
    if (process.platform != 'win32') (0, _shelljs.chmod)('+x', binaryPath);
  } catch (_) {
    /* noop */
  }
  const selenoidProcess = (0, _shelljs.exec)(`${binaryPath} -conf ./browsers.json -disable-docker`, {
    async: true,
    cwd: selenoidConfigDir
  });
  if (debug) {
    var _selenoidProcess$stdo, _selenoidProcess$stde;
    (_selenoidProcess$stdo = selenoidProcess.stdout) === null || _selenoidProcess$stdo === void 0 || _selenoidProcess$stdo.pipe(process.stdout);
    (_selenoidProcess$stde = selenoidProcess.stderr) === null || _selenoidProcess$stde === void 0 || _selenoidProcess$stde.pipe(process.stderr);
  }
  (0, _messages.subscribeOn)('shutdown', () => selenoidProcess.kill());
}
async function startSelenoidContainer(config, debug) {
  const browsers = Object.values(config.browsers).filter(browser => !browser.gridUrl);
  const images = [];
  let limit = 0;
  browsers.forEach(({
    browserName,
    version = 'latest',
    browserVersion = version,
    limit: browserLimit = 1,
    dockerImage = `selenoid/${browserName}:${browserVersion}`
  }) => {
    limit += browserLimit;
    images.push(dockerImage);
  });
  const selenoidImage = config.dockerImage;
  const pullOptions = {
    auth: config.dockerAuth,
    platform: config.dockerImagePlatform
  };
  if (config.pullImages) {
    await (0, _docker.pullImages)([selenoidImage], pullOptions);
    await (0, _docker.pullImages)(images, pullOptions);
  }

  // TODO Allow pass custom options
  const selenoidOptions = {
    ExposedPorts: {
      '4444/tcp': {}
    },
    HostConfig: {
      PortBindings: {
        '4444/tcp': [{
          HostPort: '4444'
        }]
      },
      Binds: ['/var/run/docker.sock:/var/run/docker.sock', `${await createSelenoidConfig(browsers, {
        useDocker: true
      })}:/etc/selenoid/:ro`]
    }
  };
  return (0, _docker.runImage)(selenoidImage, ['-limit', String(limit)], selenoidOptions, debug);
}