'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = validateVersionInstance;

var _ramda;

function _load_ramda() {
  return _ramda = _interopRequireDefault(require('ramda'));
}

var _validateNpmPackageName;

function _load_validateNpmPackageName() {
  return _validateNpmPackageName = _interopRequireDefault(require('validate-npm-package-name'));
}

var _validateType;

function _load_validateType() {
  return _validateType = _interopRequireDefault(require('../utils/validate-type'));
}

var _bitId;

function _load_bitId() {
  return _bitId = require('../bit-id');
}

var _versionInvalid;

function _load_versionInvalid() {
  return _versionInvalid = _interopRequireDefault(require('./exceptions/version-invalid'));
}

var _utils;

function _load_utils() {
  return _utils = require('../utils');
}

var _dependencies;

function _load_dependencies() {
  return _dependencies = require('../consumer/component/dependencies');
}

var _componentOverrides;

function _load_componentOverrides() {
  return _componentOverrides = _interopRequireDefault(require('../consumer/config/component-overrides'));
}

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

/**
 * make sure a Version instance is correct. throw an exceptions if it is not.
 */
function validateVersionInstance(version) {
  var message = 'unable to save Version object';
  var validateBitIdStr = function validateBitIdStr(bitIdStr, field) {
    var validateVersion = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;

    (0, (_validateType || _load_validateType()).default)(message, bitIdStr, field, 'string');
    var bitId = void 0;
    try {
      bitId = (_bitId || _load_bitId()).BitId.parse(bitIdStr, true);
    } catch (err) {
      throw new (_versionInvalid || _load_versionInvalid()).default(`${message}, the ${field} has an invalid Bit id`);
    }
    if (validateVersion && !bitId.hasVersion()) {
      throw new (_versionInvalid || _load_versionInvalid()).default(`${message}, the ${field} ${bitIdStr} does not have a version`);
    }
    if (!bitId.scope) throw new (_versionInvalid || _load_versionInvalid()).default(`${message}, the ${field} ${bitIdStr} does not have a scope`);
  };
  var _validateEnv = function _validateEnv(env) {
    if (!env) return;
    if (typeof env === 'string') {
      // Do not validate version - for backward compatibility
      validateBitIdStr(env, 'environment-id', false);
      return;
    }
    (0, (_validateType || _load_validateType()).default)(message, env, 'env', 'object');
    if (!env.name) {
      throw new (_versionInvalid || _load_versionInvalid()).default(`${message}, the environment is missing the name attribute`);
    }
    validateBitIdStr(env.name, 'env.name');
    if (env.files) {
      var compilerName = env.name || '';
      env.files.forEach(function (file) {
        if (!file.name) {
          throw new (_versionInvalid || _load_versionInvalid()).default(`${message}, the environment ${compilerName} has a file which missing the name attribute`);
        }
      });
    }
  };

  /**
   * Validate that the package name and version are valid
   * @param {*} packageName
   * @param {*} packageVersion
   */
  var _validatePackageDependency = function _validatePackageDependency(packageVersion, packageName) {
    var packageNameValidateResult = (0, (_validateNpmPackageName || _load_validateNpmPackageName()).default)(packageName);
    if (!packageNameValidateResult.validForNewPackages && !packageNameValidateResult.validForOldPackages) {
      var errors = packageNameValidateResult.errors || [];
      throw new (_versionInvalid || _load_versionInvalid()).default(`${packageName} is invalid package name, errors:  ${errors.join()}`);
    }
    // don't use semver.valid and semver.validRange to validate the package version because it
    // can be also a URL, Git URL or Github URL. see here: https://docs.npmjs.com/files/package.json#dependencies
    (0, (_validateType || _load_validateType()).default)(message, packageVersion, `version of "${packageName}"`, 'string');
  };
  var _validatePackageDependencies = function _validatePackageDependencies(packageDependencies) {
    (0, (_validateType || _load_validateType()).default)(message, packageDependencies, 'packageDependencies', 'object');
    (_ramda || _load_ramda()).default.forEachObjIndexed(_validatePackageDependency, packageDependencies);
  };
  var validateFile = function validateFile(file) {
    var isDist = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;

    var field = isDist ? 'dist-file' : 'file';
    (0, (_validateType || _load_validateType()).default)(message, file, field, 'object');
    if (!(0, (_utils || _load_utils()).isValidPath)(file.relativePath)) {
      throw new (_versionInvalid || _load_versionInvalid()).default(`${message}, the ${field} ${file.relativePath} is invalid`);
    }
    if (!file.name) {
      throw new (_versionInvalid || _load_versionInvalid()).default(`${message}, the ${field} ${file.relativePath} is missing the name attribute`);
    }
    if (!file.file) throw new (_versionInvalid || _load_versionInvalid()).default(`${message}, the ${field} ${file.relativePath} is missing the hash`);
    (0, (_validateType || _load_validateType()).default)(message, file.name, `${field}.name`, 'string');
    (0, (_validateType || _load_validateType()).default)(message, file.file, `${field}.file`, 'object');
    (0, (_validateType || _load_validateType()).default)(message, file.file.hash, `${field}.file.hash`, 'string');
  };

  if (!version.mainFile) throw new (_versionInvalid || _load_versionInvalid()).default(`${message}, the mainFile is missing`);
  if (!(0, (_utils || _load_utils()).isValidPath)(version.mainFile)) {
    throw new (_versionInvalid || _load_versionInvalid()).default(`${message}, the mainFile ${version.mainFile} is invalid`);
  }
  if (!version.files || !version.files.length) throw new (_versionInvalid || _load_versionInvalid()).default(`${message}, the files are missing`);
  var foundMainFile = false;
  (0, (_validateType || _load_validateType()).default)(message, version.files, 'files', 'array');
  var filesPaths = [];
  version.files.forEach(function (file) {
    validateFile(file);
    filesPaths.push(file.relativePath);
    if (file.relativePath === version.mainFile) foundMainFile = true;
  });
  if (!foundMainFile) {
    throw new (_versionInvalid || _load_versionInvalid()).default(`${message}, unable to find the mainFile ${version.mainFile} in the files list`);
  }
  var duplicateFiles = filesPaths.filter(function (file) {
    return filesPaths.filter(function (f) {
      return file.toLowerCase() === f.toLowerCase();
    }).length > 1;
  });
  if (duplicateFiles.length) {
    throw new (_versionInvalid || _load_versionInvalid()).default(`${message} the following files are duplicated ${duplicateFiles.join(', ')}`);
  }
  _validateEnv(version.compiler);
  _validateEnv(version.tester);
  _validatePackageDependencies(version.packageDependencies);
  _validatePackageDependencies(version.devPackageDependencies);
  _validatePackageDependencies(version.peerPackageDependencies);
  _validatePackageDependencies(version.compilerPackageDependencies);
  _validatePackageDependencies(version.testerPackageDependencies);
  if (version.dists && version.dists.length) {
    (0, (_validateType || _load_validateType()).default)(message, version.dists, 'dist', 'array');
    // $FlowFixMe
    version.dists.forEach(function (file) {
      validateFile(file, true);
    });
  }
  var dependenciesInstances = ['dependencies', 'devDependencies', 'compilerDependencies', 'testerDependencies'];
  dependenciesInstances.forEach(function (dependenciesType) {
    // $FlowFixMe
    if (!(version[dependenciesType] instanceof (_dependencies || _load_dependencies()).Dependencies)) {
      throw new (_versionInvalid || _load_versionInvalid()).default(`${message}, ${dependenciesType} must be an instance of Dependencies, got ${typeof version[dependenciesType]}`);
    }
  });
  version.dependencies.validate();
  version.devDependencies.validate();
  version.compilerDependencies.validate();
  version.testerDependencies.validate();
  if (!version.dependencies.isEmpty() && !version.flattenedDependencies.length) {
    throw new (_versionInvalid || _load_versionInvalid()).default(`${message}, it has dependencies but its flattenedDependencies is empty`);
  }
  if (!version.devDependencies.isEmpty() && !version.flattenedDevDependencies.length) {
    throw new (_versionInvalid || _load_versionInvalid()).default(`${message}, it has devDependencies but its flattenedDevDependencies is empty`);
  }
  if (!version.compilerDependencies.isEmpty() && !version.flattenedCompilerDependencies.length) {
    throw new (_versionInvalid || _load_versionInvalid()).default(`${message}, it has compilerDependencies but its flattenedCompilerDependencies is empty`);
  }
  if (!version.testerDependencies.isEmpty() && !version.flattenedTesterDependencies.length) {
    throw new (_versionInvalid || _load_versionInvalid()).default(`${message}, it has testerDependencies but its flattenedTesterDependencies is empty`);
  }
  var validateFlattenedDependencies = function validateFlattenedDependencies(dependencies) {
    (0, (_validateType || _load_validateType()).default)(message, dependencies, 'dependencies', 'array');
    dependencies.forEach(function (dependency) {
      if (!(dependency instanceof (_bitId || _load_bitId()).BitId)) {
        throw new (_versionInvalid || _load_versionInvalid()).default(`${message}, a flattenedDependency expected to be BitId, got ${typeof dependency}`);
      }
      if (!dependency.hasVersion()) {
        throw new (_versionInvalid || _load_versionInvalid()).default(`${message}, the flattenedDependency ${dependency.toString()} does not have a version`);
      }
    });
  };
  validateFlattenedDependencies(version.flattenedDependencies);
  validateFlattenedDependencies(version.flattenedDevDependencies);
  validateFlattenedDependencies(version.flattenedCompilerDependencies);
  validateFlattenedDependencies(version.flattenedTesterDependencies);
  if (!version.log) throw new (_versionInvalid || _load_versionInvalid()).default(`${message}, the log object is missing`);
  (0, (_validateType || _load_validateType()).default)(message, version.log, 'log', 'object');
  if (version.bindingPrefix) {
    (0, (_validateType || _load_validateType()).default)(message, version.bindingPrefix, 'bindingPrefix', 'string');
  }
  var overridesAllowedKeys = (_componentOverrides || _load_componentOverrides()).default.componentOverridesDataFields();
  var validateOverrides = function validateOverrides(dependencies, fieldName) {
    var field = `overrides.${fieldName}`;
    (0, (_validateType || _load_validateType()).default)(message, dependencies, field, 'object');
    Object.keys(dependencies).forEach(function (key) {
      (0, (_validateType || _load_validateType()).default)(message, key, `property name of ${field}`, 'string');
      (0, (_validateType || _load_validateType()).default)(message, dependencies[key], `version of "${field}.${key}"`, 'string');
    });
  };
  Object.keys(version.overrides).forEach(function (field) {
    if (!overridesAllowedKeys.includes(field)) {
      throw new (_versionInvalid || _load_versionInvalid()).default(`${message}, the "overrides" has unidentified key "${field}"`);
    }
    // $FlowFixMe
    validateOverrides(version.overrides[field], field);
  });
}