"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.HubInitiative = void 0;
const defaults_1 = require("./defaults");
const getEditorConfig_1 = require("../core/schemas/getEditorConfig");
const util_1 = require("../util");
const HubInitiatives_1 = require("./HubInitiatives");
const Catalog_1 = require("../search/Catalog");
const HubItemEntity_1 = require("../core/HubItemEntity");
const getEntityMetrics_1 = require("../metrics/getEntityMetrics");
const resolveMetric_1 = require("../metrics/resolveMetric");
const view_1 = require("./view");
const enrichEntity_1 = require("../core/enrichEntity");
const metricToEditor_1 = require("../metrics/metricToEditor");
const arcgis_rest_portal_1 = require("@esri/arcgis-rest-portal");
const convertGroupToHubGroup_1 = require("../groups/_internal/convertGroupToHubGroup");
const getEditorSlug_1 = require("../core/_internal/getEditorSlug");
const convertHubGroupToGroup_1 = require("../groups/_internal/convertHubGroupToGroup");
const hubItemEntityFromEditor_1 = require("../core/_internal/hubItemEntityFromEditor");
const get_prop_1 = require("../objects/get-prop");
const get_with_default_1 = require("../objects/get-with-default");
const set_prop_1 = require("../objects/set-prop");
/**
 * Hub Initiative Class
 */
class HubInitiative extends HubItemEntity_1.HubItemEntity {
    /**
     * Private constructor so we don't have `new` all over the place. Allows for
     * more flexibility in how we create the HubInitiativeManager over time.
     * @param context
     */
    constructor(entity, context) {
        super(entity, context);
        this._catalog = Catalog_1.Catalog.fromJson(entity.catalog, this.context);
    }
    /**
     * Catalog instance for this Initiative. Note: Do not hold direct references to this object; always access it from the Initiative.
     * @returns Catalog
     */
    get catalog() {
        return this._catalog;
    }
    /**
     * Create an instance from an IHubInitiative object
     * @param json - JSON object to create a HubInitiative from
     * @param context - ArcGIS context
     * @returns
     */
    static fromJson(json, context) {
        // merge what we have with the default values
        const pojo = this.applyDefaults(json, context);
        return new HubInitiative(pojo, context);
    }
    /**
     * Create a new HubInitiative, returning a HubInitiative instance.
     * Note: This does not persist the Initiative into the backing store
     * @param partialInitiative
     * @param context
     * @returns
     */
    static async create(partialInitiative, context, save = false) {
        const pojo = this.applyDefaults(partialInitiative, context);
        // return an instance of HubInitiative
        const instance = HubInitiative.fromJson(pojo, context);
        if (save) {
            await instance.save();
        }
        return instance;
    }
    /**
     * Fetch an Initiative from the backing store and return a HubInitiative instance.
     * @param identifier - slug or item id
     * @param context
     * @returns
     */
    static async fetch(identifier, context) {
        // fetch by id or slug
        try {
            const entity = await (0, HubInitiatives_1.fetchInitiative)(identifier, context.requestOptions);
            // create an instance of HubInitiative from the entity
            return HubInitiative.fromJson(entity, context);
        }
        catch (ex) {
            if (ex.message ===
                "CONT_0001: Item does not exist or is inaccessible.") {
                throw new Error(`Initiative not found.`);
            }
            else {
                throw ex;
            }
        }
    }
    static applyDefaults(partialInitiative, context) {
        // ensure we have the orgUrlKey
        if (!partialInitiative.orgUrlKey) {
            partialInitiative.orgUrlKey = context.portal.urlKey;
        }
        // extend the partial over the defaults
        const pojo = Object.assign(Object.assign({}, defaults_1.DEFAULT_INITIATIVE), partialInitiative);
        return pojo;
    }
    /**
     * Apply a new state to the instance
     * @param changes
     */
    update(changes) {
        if (this.isDestroyed) {
            throw new Error("HubInitiative is already destroyed.");
        }
        // merge partial onto existing entity
        this.entity = Object.assign(Object.assign({}, this.entity), changes);
        // update internal instances
        if (changes.catalog) {
            this._catalog = Catalog_1.Catalog.fromJson(this.entity.catalog, this.context);
        }
    }
    /**
     * Save the HubInitiative to the backing store.
     * Currently Initiatives are stored as Items in Portal
     * @returns
     */
    async save() {
        if (this.isDestroyed) {
            throw new Error("HubInitiative is already destroyed.");
        }
        // get the catalog, and permission configs
        this.entity.catalog = this._catalog.toJson();
        if (this.entity.id) {
            // update it
            this.entity = await (0, HubInitiatives_1.updateInitiative)(this.entity, this.context.userRequestOptions);
        }
        else {
            // create it
            this.entity = await (0, HubInitiatives_1.createInitiative)(this.entity, this.context.userRequestOptions);
        }
        // call the after save hook on superclass
        await super.afterSave();
        return;
    }
    /**
     * Delete the HubInitiative from the store
     * set a flag to indicate that it is destroyed
     * @returns
     */
    async delete() {
        if (this.isDestroyed) {
            throw new Error("HubInitiative is already destroyed.");
        }
        this.isDestroyed = true;
        // Delegate to module fn
        await (0, HubInitiatives_1.deleteInitiative)(this.entity.id, this.context.userRequestOptions);
    }
    /**
     * Resolve a single metric for this metric
     * @param metricId
     * @returns
     */
    resolveMetric(metricId) {
        const metrics = (0, getEntityMetrics_1.getEntityMetrics)(this.entity);
        const metric = metrics.find((m) => m.id === metricId);
        // TODO: Add caching
        if (metric) {
            return (0, resolveMetric_1.resolveMetric)(metric, this.context);
        }
        else {
            throw new Error(`Metric ${metricId} not found.`);
        }
    }
    /**
     * Convert the initiative entity into a card view model that
     * can be consumed by the suite of hub gallery components
     *
     * @param opts view model options
     */
    convertToCardModel(opts) {
        return (0, view_1.initiativeToCardModel)(this.entity, this.context, opts);
    }
    /*
     * Get a specifc editor config for the HubInitiative entity.
     * @param i18nScope translation scope to be interpolated into the uiSchema
     * @param type editor type - corresonds to the returned uiSchema
     * @param options optional hash of dynamic uiSchema element options
     */
    async getEditorConfig(i18nScope, type) {
        // delegate to the schema subsystem
        return (0, getEditorConfig_1.getEditorConfig)(i18nScope, type, this.entity, this.context);
    }
    /**
     * Return the initiative as an editor object
     * @param editorContext
     * @returns
     */
    async toEditor(editorContext = {}, include = []) {
        // 1. optionally enrich entity and cast to editor
        const editor = include.length
            ? (await (0, enrichEntity_1.enrichEntity)((0, util_1.cloneObject)(this.entity), include, this.context.hubRequestOptions))
            : (0, util_1.cloneObject)(this.entity);
        // 2. handle metrics
        const metrics = (0, getEntityMetrics_1.getEntityMetrics)(this.entity);
        const metric = metrics.find((m) => m.id === editorContext.metricId);
        const displays = (0, get_with_default_1.getWithDefault)(this.entity, "view.metricDisplays", []);
        const displayConfig = displays.find((display) => display.metricId === editorContext.metricId) || {};
        editor._metric = (0, metricToEditor_1.metricToEditor)(metric, displayConfig);
        // 3. handle association group
        const assocGroupId = (0, get_prop_1.getProp)(this.entity, "associations.groupId");
        if (assocGroupId) {
            const associationGroup = await (0, arcgis_rest_portal_1.getGroup)(assocGroupId, this.context.requestOptions);
            const hubAssociationGroup = (0, convertGroupToHubGroup_1.convertGroupToHubGroup)(associationGroup, null, this.context.userRequestOptions);
            const _associations = {
                groupAccess: hubAssociationGroup.access,
                membershipAccess: hubAssociationGroup.membershipAccess,
            };
            editor._associations = _associations;
        }
        // 4. slug life
        editor._slug = (0, getEditorSlug_1.getEditorSlug)(this.entity);
        return editor;
    }
    /**
     * Load the initiative from the editor object
     * @param editor
     * @returns
     */
    async fromEditor(editor) {
        var _a;
        const _associations = editor._associations;
        delete editor._associations;
        // 1. delegate to an item-specific fromEditor util to
        // handle shared "fromEditor" logic
        const res = await (0, hubItemEntityFromEditor_1.hubItemEntityFromEditor)(editor, this.context);
        const initiative = res.entity;
        // iterate over the res object keys and set the values
        // on the HubInitiative instance
        Object.entries(res).forEach(([key, value]) => {
            (0, set_prop_1.setProp)(key, value, this);
        });
        // 2. handle initiative-specific operations
        // a. handle association group settings
        const assocGroupId = (_a = initiative.associations) === null || _a === void 0 ? void 0 : _a.groupId;
        if (assocGroupId && _associations) {
            const associationGroup = (0, convertHubGroupToGroup_1.convertHubGroupToGroup)(_associations);
            // handle group access
            if (_associations.groupAccess) {
                await (0, arcgis_rest_portal_1.updateGroup)({
                    group: {
                        id: assocGroupId,
                        access: _associations.groupAccess,
                    },
                    authentication: this.context.hubRequestOptions.authentication,
                });
            }
            // handle membership access
            if (_associations.membershipAccess) {
                await (0, arcgis_rest_portal_1.updateGroup)({
                    group: {
                        id: assocGroupId,
                        membershipAccess: associationGroup.membershipAccess,
                        clearEmptyFields: true,
                    },
                    authentication: this.context.hubRequestOptions.authentication,
                });
            }
        }
        // save or create the entity
        this.entity = initiative;
        await this.save();
        return this.entity;
    }
}
exports.HubInitiative = HubInitiative;
//# sourceMappingURL=HubInitiative.js.map