"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.deleteSavedWorkspace = deleteSavedWorkspace;
exports.findSavedWorkspace = findSavedWorkspace;
exports.getEmptyWorkspace = getEmptyWorkspace;
exports.getSavedWorkspace = getSavedWorkspace;
exports.saveSavedWorkspace = saveSavedWorkspace;
var _lodash = require("lodash");
var _i18n = require("@kbn/i18n");
var _public = require("@kbn/saved-objects-plugin/public");
var _public2 = require("@kbn/kibana-utils-plugin/public");
var _content_management = require("../../common/content_management");
var _saved_workspace_references = require("../services/persistence/saved_workspace_references");
var _saved_objects_utils = require("./saved_objects_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; you may not use this file except in compliance with the Elastic License
 * 2.0.
 */

const savedWorkspaceType = 'graph-workspace';
const mapping = {
  title: 'text',
  description: 'text',
  numLinks: 'integer',
  numVertices: 'integer',
  version: 'integer',
  wsState: 'json'
};
const defaultsProps = {
  title: _i18n.i18n.translate('xpack.graph.savedWorkspace.workspaceNameTitle', {
    defaultMessage: 'New Graph Workspace'
  }),
  numLinks: 0,
  numVertices: 0,
  wsState: '{}',
  version: 1
};
const urlFor = (basePath, id) => basePath.prepend(`/app/graph#/workspace/${encodeURIComponent(id)}`);
function mapHits(hit, url) {
  const source = hit.attributes;
  source.id = hit.id;
  source.url = url;
  source.updatedAt = hit.updatedAt;
  source.icon = 'cluster'; // maybe there's a better choice here?
  return source;
}
function findSavedWorkspace({
  contentClient,
  basePath
}, searchString, size = 100) {
  return contentClient.search({
    contentTypeId: _content_management.CONTENT_ID,
    query: {
      text: searchString ? `${searchString}*` : ''
    }
  }).then(resp => {
    return {
      total: resp.pagination.total,
      hits: resp.hits.map(hit => mapHits(hit, urlFor(basePath, hit.id)))
    };
  });
}
function getEmptyWorkspace() {
  return {
    savedObject: {
      displayName: 'graph workspace',
      getEsType: () => savedWorkspaceType,
      ...defaultsProps
    }
  };
}
async function getSavedWorkspace(contentClient, id) {
  const resolveResult = await contentClient.get({
    contentTypeId: _content_management.CONTENT_ID,
    id
  });
  const resp = resolveResult.item;
  if (!resp.attributes) {
    throw new _public2.SavedObjectNotFound(savedWorkspaceType, id || '');
  }
  const savedObject = {
    id,
    displayName: 'graph workspace',
    getEsType: () => savedWorkspaceType,
    _source: (0, _lodash.cloneDeep)({
      ...resp.attributes
    })
  };

  // assign the defaults to the response
  (0, _lodash.defaults)(savedObject._source, defaultsProps);

  // transform the source using JSON.parse
  if (savedObject._source.wsState) {
    savedObject._source.wsState = JSON.parse(savedObject._source.wsState);
  }

  // Give obj all of the values in _source.fields
  (0, _lodash.assign)(savedObject, savedObject._source);
  savedObject.lastSavedTitle = savedObject.title;
  if (resp.references && resp.references.length > 0) {
    (0, _saved_workspace_references.injectReferences)(savedObject, resp.references);
  }
  const sharingSavedObjectProps = {
    outcome: resolveResult.meta.outcome,
    aliasTargetId: resolveResult.meta.aliasTargetId,
    aliasPurpose: resolveResult.meta.aliasPurpose
  };
  return {
    savedObject,
    sharingSavedObjectProps
  };
}
function deleteSavedWorkspace(contentClient, ids) {
  return Promise.all(ids.map(id => contentClient.delete({
    contentTypeId: _content_management.CONTENT_ID,
    id
  })));
}
async function saveSavedWorkspace(savedObject, {
  confirmOverwrite = false,
  isTitleDuplicateConfirmed = false,
  onTitleDuplicate
} = {}, services) {
  let attributes = {};
  (0, _lodash.forOwn)(mapping, (fieldType, fieldName) => {
    const savedObjectFieldVal = savedObject[fieldName];
    if (savedObjectFieldVal != null) {
      attributes[fieldName] = fieldName === 'wsState' ? JSON.stringify(savedObjectFieldVal) : savedObjectFieldVal;
    }
  });
  const extractedRefs = (0, _saved_workspace_references.extractReferences)({
    attributes,
    references: []
  });
  const references = extractedRefs.references;
  attributes = extractedRefs.attributes;
  if (!references) {
    throw new Error('References not returned from extractReferences');
  }

  // Save the original id in case the save fails.
  const originalId = savedObject.id;
  try {
    // Read https://github.com/elastic/kibana/issues/9056 and
    // https://github.com/elastic/kibana/issues/9012 for some background into why this copyOnSave variable
    // exists.
    // The goal is to move towards a better rename flow, but since our users have been conditioned
    // to expect a 'save as' flow during a rename, we are keeping the logic the same until a better
    // UI/UX can be worked out.
    if (savedObject.copyOnSave) {
      delete savedObject.id;
    }
    savedObject.isSaving = true;
    await (0, _saved_objects_utils.checkForDuplicateTitle)(savedObject, isTitleDuplicateConfirmed, onTitleDuplicate, services);
    const createOpt = {
      id: savedObject.id,
      migrationVersion: savedObject.migrationVersion,
      references
    };
    const resp = confirmOverwrite ? await (0, _saved_objects_utils.saveWithConfirmation)(attributes, savedObject, createOpt, services) : savedObject.id ? await services.contentClient.update({
      contentTypeId: _content_management.CONTENT_ID,
      id: savedObject.id,
      data: {
        ...extractedRefs.attributes
      },
      options: {
        references: extractedRefs.references
      }
    }) : await services.contentClient.create({
      contentTypeId: _content_management.CONTENT_ID,
      data: attributes,
      options: {
        references: createOpt.references,
        overwrite: true
      }
    });
    savedObject.id = resp.item.id;
    savedObject.isSaving = false;
    savedObject.lastSavedTitle = savedObject.title;
    return savedObject.id;
  } catch (err) {
    savedObject.isSaving = false;
    savedObject.id = originalId;
    if ((0, _public.isErrorNonFatal)(err)) {
      return '';
    }
    return Promise.reject(err);
  }
}