"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.DocumentDowngradePipeline = void 0;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _lodash = require("lodash");
var _semver = _interopRequireDefault(require("semver"));
var _types = require("../types");
var _utils = require("./utils");
/*
 * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
 * or more contributor license agreements. Licensed under the Elastic License
 * 2.0 and the Server Side Public License, v 1; you may not use this file except
 * in compliance with, at your election, the Elastic License 2.0 or the Server
 * Side Public License, v 1.
 */

class DocumentDowngradePipeline {
  constructor({
    document,
    kibanaVersion,
    typeTransforms,
    targetTypeVersion,
    targetCoreVersion
  }) {
    (0, _defineProperty2.default)(this, "document", void 0);
    (0, _defineProperty2.default)(this, "kibanaVersion", void 0);
    (0, _defineProperty2.default)(this, "originalDoc", void 0);
    (0, _defineProperty2.default)(this, "typeTransforms", void 0);
    (0, _defineProperty2.default)(this, "targetTypeVersion", void 0);
    (0, _defineProperty2.default)(this, "targetCoreVersion", void 0);
    this.originalDoc = document;
    this.kibanaVersion = kibanaVersion;
    this.document = (0, _lodash.cloneDeep)(document);
    this.typeTransforms = typeTransforms;
    this.targetTypeVersion = targetTypeVersion;
    this.targetCoreVersion = targetCoreVersion;
  }
  run() {
    (0, _utils.assertValidCoreVersion)({
      document: this.document,
      kibanaVersion: this.kibanaVersion
    });
    this.assertCompatibility();
    for (const transform of this.getPendingTransforms()) {
      if (!transform.transformDown) {
        continue;
      }
      const {
        transformedDoc
      } = transform.transformDown(this.document);
      if (this.document.type !== this.originalDoc.type) {
        throw new Error(`Changing a document's type during a migration is not supported.`);
      }
      this.document = (0, _utils.applyVersion)({
        document: transformedDoc,
        transform
      });
    }
    this.document = this.ensureVersion(this.document);
    this.document = this.applyVersionSchema(this.document);
    return {
      document: this.document,
      additionalDocs: []
    };
  }
  getPendingTransforms() {
    const {
      transforms
    } = this.typeTransforms;
    return transforms.reverse().filter(transform => this.isPendingTransform(transform));
  }
  isPendingTransform({
    transformType,
    version
  }) {
    const {
      coreMigrationVersion,
      typeMigrationVersion
    } = this.document;
    switch (transformType) {
      // reference and convert type transforms were deprecated before downward conversion were a thing
      // so we will never need to revert such type of transforms (and they didn't implement a down conversion)
      case _types.TransformType.Reference:
      case _types.TransformType.Convert:
        return false;
      // including core transforms if targetCoreVersion is specified
      case _types.TransformType.Core:
        return this.targetCoreVersion && (coreMigrationVersion == null || _semver.default.gt(coreMigrationVersion, this.targetCoreVersion)) && _semver.default.gt(version, this.targetCoreVersion);
      // including migrate transforms between the targetTypeVersion and the typeMigrationVersion
      case _types.TransformType.Migrate:
        return (typeMigrationVersion == null || _semver.default.gte(typeMigrationVersion, version)) && _semver.default.gt(version, this.targetTypeVersion);
    }
  }

  /**
   * Verifies that the current document version is not greater than the version supported by Kibana.
   * And that the targetTypeVersion is not greater than the document's
   */
  assertCompatibility() {
    const {
      typeMigrationVersion: currentVersion
    } = this.document;
    if (currentVersion && _semver.default.gt(this.targetTypeVersion, currentVersion)) {
      throw new Error(`Trying to transform down to a higher version: ${currentVersion} to ${this.targetTypeVersion}`);
    }
  }
  ensureVersion({
    coreMigrationVersion: currentCoreMigrationVersion,
    typeMigrationVersion: currentTypeMigrationVersion,
    ...document
  }) {
    const coreMigrationVersion = this.targetCoreVersion || currentCoreMigrationVersion;
    return {
      ...document,
      typeMigrationVersion: this.targetTypeVersion,
      ...(coreMigrationVersion ? {
        coreMigrationVersion
      } : {})
    };
  }
  applyVersionSchema(doc) {
    const targetVersion = this.targetTypeVersion;
    const versionSchema = this.typeTransforms.versionSchemas[targetVersion];
    if (versionSchema) {
      return versionSchema(doc);
    }
    return doc;
  }
}
exports.DocumentDowngradePipeline = DocumentDowngradePipeline;