"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.extensions = exports.downloadBinary = exports.LOCALHOST_REGEXP = void 0;
exports.getCreeveyCache = getCreeveyCache;
exports.isShuttingDown = exports.isInsideDocker = void 0;
exports.readDirRecursive = readDirRecursive;
exports.removeProps = removeProps;
exports.runSequence = runSequence;
exports.shouldSkip = shouldSkip;
exports.shouldSkipByOption = shouldSkipByOption;
exports.shutdown = shutdown;
exports.shutdownWorkers = shutdownWorkers;
exports.skipOptionKeys = void 0;
exports.testsToImages = testsToImages;
var _fs = require("fs");
var _cluster = _interopRequireDefault(require("cluster"));
var _types = require("../types");
var _messages = require("./messages");
var _findCacheDir = _interopRequireDefault(require("find-cache-dir"));
var _https = require("https");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
const isShuttingDown = exports.isShuttingDown = {
  current: false
};
const LOCALHOST_REGEXP = exports.LOCALHOST_REGEXP = /(localhost|127\.0\.0\.1)/i;
const extensions = exports.extensions = ['.js', '.jsx', '.ts', '.tsx'];
const skipOptionKeys = exports.skipOptionKeys = ['in', 'kinds', 'stories', 'tests', 'reason'];
function matchBy(pattern, value) {
  return typeof pattern == 'string' && pattern == value || Array.isArray(pattern) && pattern.includes(value) || pattern instanceof RegExp && pattern.test(value) || !(0, _types.isDefined)(pattern);
}
function shouldSkip(browser, meta, skipOptions, test) {
  if (typeof skipOptions != 'object') {
    return skipOptions;
  }
  for (const skipKey in skipOptions) {
    const reason = shouldSkipByOption(browser, meta, skipOptions[skipKey], skipKey, test);
    if (reason) return reason;
  }
  return false;
}
function shouldSkipByOption(browser, meta, skipOption, reason, test) {
  if (Array.isArray(skipOption)) {
    for (const skip of skipOption) {
      const result = shouldSkipByOption(browser, meta, skip, reason, test);
      if (result) return result;
    }
    return false;
  }
  const {
    in: browsers,
    kinds,
    stories,
    tests
  } = skipOption;
  const {
    kind,
    story
  } = meta;
  const skipByBrowser = matchBy(browsers, browser);
  const skipByKind = matchBy(kinds, kind);
  const skipByStory = matchBy(stories, story);
  const skipByTest = !(0, _types.isDefined)(test) || matchBy(tests, test);
  return skipByBrowser && skipByKind && skipByStory && skipByTest && reason;
}
async function shutdownWorkers() {
  isShuttingDown.current = true;
  await Promise.all(Object.values(_cluster.default.workers ?? {}).filter(_types.isDefined).filter(worker => worker.isConnected()).map(worker => new Promise(resolve => {
    const timeout = setTimeout(() => worker.kill(), 10000);
    worker.on('exit', () => {
      clearTimeout(timeout);
      resolve();
    });
    (0, _messages.sendShutdownMessage)(worker);
  })));
  (0, _messages.emitShutdownMessage)();
}
function shutdown() {
  // eslint-disable-next-line no-process-exit
  process.exit();
}
function getCreeveyCache() {
  return (0, _findCacheDir.default)({
    name: 'creevey',
    cwd: __dirname
  });
}
async function runSequence(seq, predicate) {
  for (const fn of seq) {
    if (predicate()) await fn();
  }
}
function testsToImages(tests) {
  return new Set([].concat(...tests.filter(_types.isDefined).map(({
    browser,
    testName,
    storyPath,
    results
  }) => {
    var _results$slice$;
    return Object.keys((results === null || results === void 0 || (_results$slice$ = results.slice(-1)[0]) === null || _results$slice$ === void 0 ? void 0 : _results$slice$.images) ?? {}).map(image => `${[...storyPath, testName, browser, browser == image ? undefined : image].filter(_types.isDefined).join('/')}.png`);
  })));
}

// https://tuhrig.de/how-to-know-you-are-inside-a-docker-container/
const isInsideDocker = exports.isInsideDocker = (0, _fs.existsSync)('/proc/1/cgroup') && /docker/.test((0, _fs.readFileSync)('/proc/1/cgroup', 'utf8'));
const downloadBinary = (downloadUrl, destination) => new Promise((resolve, reject) => (0, _https.get)(downloadUrl, response => {
  if (response.statusCode == 302) {
    const {
      location
    } = response.headers;
    if (!location) return reject(new Error(`Couldn't download selenoid. Status code: ${response.statusCode ?? 'UNKNOWN'}`));
    return resolve(downloadBinary(location, destination));
  }
  if (response.statusCode != 200) return reject(new Error(`Couldn't download selenoid. Status code: ${response.statusCode ?? 'UNKNOWN'}`));
  const fileStream = (0, _fs.createWriteStream)(destination);
  response.pipe(fileStream);
  fileStream.on('finish', () => {
    fileStream.close();
    resolve();
  });
  fileStream.on('error', error => {
    (0, _fs.unlink)(destination, _types.noop);
    reject(error);
  });
}));
exports.downloadBinary = downloadBinary;
function removeProps(obj, propPath) {
  const [prop, ...restPath] = propPath;
  if (restPath.length > 0) {
    if (typeof prop == 'string') obj[prop] && removeProps(obj[prop], restPath);
    if ((0, _types.isFunction)(prop)) Object.keys(obj).filter(prop).forEach(key => obj[key] && removeProps(obj[key], restPath));
  } else {
    if (typeof prop == 'string') delete obj[prop];
    if ((0, _types.isFunction)(prop)) Object.keys(obj).filter(prop).forEach(key => delete obj[key]);
  }
}
function readDirRecursive(dirPath) {
  return [].concat(...(0, _fs.readdirSync)(dirPath, {
    withFileTypes: true
  }).map(dirent => dirent.isDirectory() ? readDirRecursive(`${dirPath}/${dirent.name}`) : [`${dirPath}/${dirent.name}`]));
}