"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createContent = createContent;
exports.updateContent = updateContent;
exports.deleteContent = deleteContent;
exports.editorToContent = editorToContent;
const arcgis_rest_portal_1 = require("@esri/arcgis-rest-portal");
const PropertyMapper_1 = require("../core/_internal/PropertyMapper");
const getPropertyMap_1 = require("./_internal/getPropertyMap");
const util_1 = require("../util");
const modelToHubEditableContent_1 = require("./modelToHubEditableContent");
const arcgis_rest_feature_service_1 = require("@esri/arcgis-rest-feature-service");
const arcgis_rest_feature_service_2 = require("@esri/arcgis-rest-feature-service");
const hostedServiceUtils_1 = require("./hostedServiceUtils");
const manageSchedule_1 = require("./manageSchedule");
const internalContentUtils_1 = require("./_internal/internalContentUtils");
const getDownloadFlow_1 = require("../downloads/_internal/getDownloadFlow");
const getDownloadConfiguration_1 = require("../downloads/getDownloadConfiguration");
const shouldShowDownloadsConfiguration_1 = require("./_internal/shouldShowDownloadsConfiguration");
const createOrUpdateEntitySettings_1 = require("../core/_internal/createOrUpdateEntitySettings");
const utils_1 = require("../discussions/utils");
const createModel_1 = require("../models/createModel");
const updateModel_1 = require("../models/updateModel");
const get_prop_1 = require("../objects/get-prop");
const set_prop_1 = require("../objects/set-prop");
const deepEqual_1 = require("../objects/deepEqual");
const serviceCapabilities_1 = require("./enums/serviceCapabilities");
// TODO: move this to defaults?
const DEFAULT_CONTENT_MODEL = {
    item: {
        title: "No Title Provided",
        description: "",
        snippet: "",
        tags: [],
        typeKeywords: [],
    },
    data: null,
};
/**
 * @private
 * Create a new Hub Content item
 *
 * Minimal properties are name and org
 *
 */
async function createContent(partialContent, requestOptions) {
    // let resources;
    // merge incoming with the default
    // this expansion solves the typing somehow
    const content = Object.assign({}, partialContent);
    content.typeKeywords = (0, utils_1.setDiscussableKeyword)(content.typeKeywords, content.isDiscussable);
    // Map project object onto a default project Model
    const mapper = new PropertyMapper_1.PropertyMapper((0, getPropertyMap_1.getPropertyMap)());
    // create model from object, using the default model as a starting point
    let model = mapper.entityToStore(content, (0, util_1.cloneObject)(DEFAULT_CONTENT_MODEL));
    // TODO: if we have resources disconnect them from the model for now.
    // if (model.resources) {
    //   resources = configureBaseResources(
    //     cloneObject(model.resources),
    //     EntityResourceMap
    //   );
    //   delete model.resources;
    // }
    // create the item
    model = await (0, createModel_1.createModel)(model, requestOptions);
    // TODO: if we have resources, create them, then re-attach them to the model
    // if (resources) {
    //   model = await upsertModelResources(model, resources, requestOptions);
    // }
    // map the model back into a IHubEditableContent
    const newContent = mapper.storeToEntity(model, {});
    // create the entity settings
    const entitySetting = await (0, createOrUpdateEntitySettings_1.createOrUpdateEntitySettings)(newContent, requestOptions);
    newContent.entitySettingsId = entitySetting.id;
    newContent.discussionSettings = entitySetting.settings.discussions;
    // TODO:
    // newContent = computeProps(model, newContent, requestOptions);
    // and return it
    return newContent;
}
/**
 * @private
 * Update a Hub Content
 * @param content
 * @param requestOptions
 */
async function updateContent(content, requestOptions) {
    // Get the backing item
    // NOTE: We can't just call `getModel` because we need to be able
    // to properly handle other types like PDFs that don't have JSON data
    const item = await (0, arcgis_rest_portal_1.getItem)(content.id, requestOptions);
    const model = { item };
    content.typeKeywords = (0, utils_1.setDiscussableKeyword)(content.typeKeywords, content.isDiscussable);
    // create the PropertyMapper
    const mapper = new PropertyMapper_1.PropertyMapper((0, getPropertyMap_1.getPropertyMap)());
    // Note: Although we are fetching the model, and applying changes onto it,
    // we are not attempting to handle "concurrent edit" conflict resolution
    // but this is where we would apply that sort of logic
    const modelToUpdate = mapper.entityToStore(content, model);
    // NOTE: Product has asked that we display a _disabled_ downloads configuration for
    // certain types of entities, but not allow users to change any settings. The following
    // checks are in place to make sure we don't accidentally save configurations in
    // situations where we shouldn't
    const downloadFlow = (0, getDownloadFlow_1.getDownloadFlow)(content);
    const updatedFormats = (0, get_prop_1.getProp)(content, "extendedProps.downloads.formats");
    const isMainEntityExtractDisabled = (0, hostedServiceUtils_1.isHostedFeatureServiceMainEntity)(content) &&
        downloadFlow !== "createReplica";
    const wasDownloadsConfigurationDisplayed = (0, shouldShowDownloadsConfiguration_1.shouldShowDownloadsConfiguration)(content);
    if (wasDownloadsConfigurationDisplayed && // whether the downloads configuration was displayed
        downloadFlow && // whether the entity can be downloaded
        updatedFormats && // whether download format configuration is present
        !isMainEntityExtractDisabled) {
        const updatedDownloadsConfiguration = (0, util_1.cloneObject)(content.extendedProps.downloads);
        (0, set_prop_1.setProp)("item.properties.downloads", updatedDownloadsConfiguration, modelToUpdate, true);
    }
    // TODO: if we have resources disconnect them from the model for now.
    // if (modelToUpdate.resources) {
    //   resources = configureBaseResources(
    //     cloneObject(modelToUpdate.resources),
    //     EntityResourceMap
    //   );
    //   delete modelToUpdate.resources;
    // }
    // update the backing item
    const updatedModel = await (0, updateModel_1.updateModel)(modelToUpdate, requestOptions);
    // update enrichment values
    const enrichments = {};
    // NOTE: Due to platform limitations, The only way we can guarantee that a user can update the
    // service definition without performing a no-op update is if the user has edit rights to the
    // "main" item of the hosted feature service. Just like AGO, we don't allow users to update the
    // service if the current item is just a reference to a pre-existing service.
    if ((0, hostedServiceUtils_1.isHostedFeatureServiceMainEntity)(content)) {
        const currentDefinition = await (0, arcgis_rest_feature_service_1.getService)(Object.assign(Object.assign({}, requestOptions), { url: content.url }));
        const currentServerExtractEnabled = (0, hostedServiceUtils_1.hasServiceCapability)(serviceCapabilities_1.ServiceCapabilities.EXTRACT, currentDefinition);
        // To avoid over-updating the service, we only fire an update call if Extract has changed
        // TODO: Change the edit flow and entity schema to read from `extendedProps.serverExtractCapability`
        if (currentServerExtractEnabled !== content.serverExtractCapability) {
            const updatedDefinition = (0, hostedServiceUtils_1.toggleServiceCapability)(serviceCapabilities_1.ServiceCapabilities.EXTRACT, currentDefinition);
            const updatedServiceCapabilities = {
                capabilities: updatedDefinition.capabilities,
            };
            await (0, arcgis_rest_feature_service_2.updateServiceDefinition)((0, arcgis_rest_feature_service_1.parseServiceUrl)(content.url), {
                authentication: requestOptions.authentication,
                updateDefinition: updatedServiceCapabilities,
            });
            enrichments.server = updatedDefinition;
        }
        else {
            enrichments.server = currentDefinition;
        }
    }
    if ((0, manageSchedule_1.isDownloadSchedulingAvailable)(requestOptions, content.access)) {
        // if schedule has "Force Update" checked and clicked save, initiate an update
        if ((0, deepEqual_1.deepEqual)(content._forceUpdate, [true])) {
            // [true]
            await (0, internalContentUtils_1.forceUpdateContent)(item.id, requestOptions);
        }
        delete content._forceUpdate;
        await (0, manageSchedule_1.maybeUpdateSchedule)(content, requestOptions);
    }
    // map back into a content
    const updatedContent = (0, modelToHubEditableContent_1.modelToHubEditableContent)(updatedModel, requestOptions, enrichments, content);
    // create or update entity settings
    const entitySetting = await (0, createOrUpdateEntitySettings_1.createOrUpdateEntitySettings)(updatedContent, requestOptions);
    updatedContent.entitySettingsId = entitySetting.id;
    updatedContent.discussionSettings = entitySetting.settings.discussions;
    return updatedContent;
}
/**
 * @private
 * Remove a Hub Content
 * @param id
 * @param requestOptions
 */
async function deleteContent(id, requestOptions) {
    const ro = Object.assign(Object.assign({}, requestOptions), { id });
    await (0, arcgis_rest_portal_1.removeItem)(ro);
    return;
}
/**
 * Convert a IHubContentEditor back to an IHubContent
 * @param editor
 * @param portal
 * @returns
 */
function editorToContent(editor, _portal) {
    var _a;
    // Clone the editor to prevent mutation
    const clonedEditor = (0, util_1.cloneObject)(editor);
    // Remove unneeded properties
    delete clonedEditor.downloadFormats;
    // Cast the editor to a content
    const content = (0, util_1.cloneObject)(clonedEditor);
    // Conditionally set the downloads configuration. We only want
    // to set the configuration if the entity is actually downloadable
    const downloadFlow = (0, getDownloadFlow_1.getDownloadFlow)(content);
    if (downloadFlow && editor.downloadFormats) {
        const downloadConfiguration = (0, getDownloadConfiguration_1.getDownloadConfiguration)(content);
        // Convert the download format display objects to the stored format
        const forStorage = editor.downloadFormats.map((format) => {
            const noLabel = (0, util_1.cloneObject)(format);
            delete noLabel.label;
            return noLabel;
        });
        downloadConfiguration.formats = forStorage;
        (0, set_prop_1.setProp)("extendedProps.downloads", downloadConfiguration, content, true);
    }
    // copy the location extent up one level
    content.extent = ((_a = editor.location) === null || _a === void 0 ? void 0 : _a.extent) || [];
    return content;
}
//# sourceMappingURL=edit.js.map