"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createInitiative = createInitiative;
exports.updateInitiative = updateInitiative;
exports.fetchInitiative = fetchInitiative;
exports.deleteInitiative = deleteInitiative;
exports.convertItemToInitiative = convertItemToInitiative;
exports.enrichInitiativeSearchResult = enrichInitiativeSearchResult;
exports.getPendingProjectsQuery = getPendingProjectsQuery;
// Note - we separate these imports so we can cleanly spy on things in tests
const slugs_1 = require("../items/slugs");
const arcgis_rest_portal_1 = require("@esri/arcgis-rest-portal");
const PropertyMapper_1 = require("../core/_internal/PropertyMapper");
const parseInclude_1 = require("../search/_internal/parseInclude");
const _enrichments_1 = require("../items/_enrichments");
const defaults_1 = require("./defaults");
const getPropertyMap_1 = require("./_internal/getPropertyMap");
const computeProps_1 = require("./_internal/computeProps");
const combineQueries_1 = require("../search/combineQueries");
const getTypeWithKeywordQuery_1 = require("../associations/internal/getTypeWithKeywordQuery");
const negateGroupPredicates_1 = require("../search/negateGroupPredicates");
const computeLinks_1 = require("./_internal/computeLinks");
const internalContentUtils_1 = require("../content/_internal/internalContentUtils");
const setEntityStatusKeyword_1 = require("../utils/internal/setEntityStatusKeyword");
const ensureUniqueEntitySlug_1 = require("../items/_internal/ensureUniqueEntitySlug");
const utils_1 = require("../discussions/utils");
const util_1 = require("../util");
const is_guid_1 = require("../utils/is-guid");
const get_family_1 = require("../content/get-family");
const get_prop_1 = require("../objects/get-prop");
const map_by_1 = require("../utils/map-by");
const createModel_1 = require("../models/createModel");
const fetchModelFromItem_1 = require("../models/fetchModelFromItem");
const getModel_1 = require("../models/getModel");
const updateModel_1 = require("../models/updateModel");
/**
 * @private
 * Create a new Hub Initiative item
 *
 * Minimal properties are name and orgUrlKey
 *
 * @param partialInitiative
 * @param requestOptions
 */
async function createInitiative(partialInitiative, requestOptions) {
    // merge incoming with the default
    // this expansion solves the typing somehow
    const initiative = Object.assign(Object.assign({}, defaults_1.DEFAULT_INITIATIVE), partialInitiative);
    // ensure orgUrlKey is lowercase
    initiative.orgUrlKey = initiative.orgUrlKey.toLowerCase();
    // Create a slug from the title if one is not passed in
    if (!initiative.slug) {
        initiative.slug = (0, slugs_1.constructSlug)(initiative.name, initiative.orgUrlKey);
    }
    // Ensure slug is  unique
    await (0, ensureUniqueEntitySlug_1.ensureUniqueEntitySlug)(initiative, requestOptions);
    // add the status keyword
    initiative.typeKeywords = (0, setEntityStatusKeyword_1.setEntityStatusKeyword)(initiative.typeKeywords, initiative.status);
    initiative.typeKeywords = (0, utils_1.setDiscussableKeyword)(initiative.typeKeywords, initiative.isDiscussable);
    // Map initiative object onto a default initiative 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(initiative, (0, util_1.cloneObject)(defaults_1.DEFAULT_INITIATIVE_MODEL));
    // create the item
    model = await (0, createModel_1.createModel)(model, requestOptions);
    // map the model back into a IHubInitiative
    let newInitiative = mapper.storeToEntity(model, {});
    newInitiative = (0, computeProps_1.computeProps)(model, newInitiative, requestOptions);
    // and return it
    return newInitiative;
}
/**
 * @private
 * Update a Hub Initiative
 * @param initiative
 * @param requestOptions
 */
async function updateInitiative(initiative, requestOptions) {
    // verify that the slug is unique, excluding the current initiative
    await (0, ensureUniqueEntitySlug_1.ensureUniqueEntitySlug)(initiative, requestOptions);
    // update the status keyword
    initiative.typeKeywords = (0, setEntityStatusKeyword_1.setEntityStatusKeyword)(initiative.typeKeywords, initiative.status);
    initiative.typeKeywords = (0, utils_1.setDiscussableKeyword)(initiative.typeKeywords, initiative.isDiscussable);
    // get the backing item & data
    const model = await (0, getModel_1.getModel)(initiative.id, requestOptions);
    // 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(initiative, model);
    // update the backing item
    const updatedModel = await (0, updateModel_1.updateModel)(modelToUpdate, requestOptions);
    // now map back into an initiative and return that
    let updatedInitiative = mapper.storeToEntity(updatedModel, initiative);
    updatedInitiative = (0, computeProps_1.computeProps)(model, updatedInitiative, requestOptions);
    // the casting is needed because modelToObject returns a `Partial<T>`
    // where as this function returns a `T`
    return updatedInitiative;
}
/**
 * @private
 * Get a Hub Initiative by id or slug
 * @param identifier item id or slug
 * @param requestOptions
 */
function fetchInitiative(identifier, requestOptions) {
    let getPrms;
    if ((0, is_guid_1.isGuid)(identifier)) {
        // get item by id
        getPrms = (0, arcgis_rest_portal_1.getItem)(identifier, requestOptions);
    }
    else {
        getPrms = (0, slugs_1.getItemBySlug)(identifier, requestOptions);
    }
    return getPrms.then((item) => {
        if (!item)
            return null;
        return convertItemToInitiative(item, requestOptions);
    });
}
/**
 * @private
 * Remove a Hub Initiative
 * @param id
 * @param requestOptions
 */
async function deleteInitiative(id, requestOptions) {
    const ro = Object.assign(Object.assign({}, requestOptions), { id });
    await (0, arcgis_rest_portal_1.removeItem)(ro);
    return;
}
/**
 * @private
 * Convert an Hub Initiative Item into a Hub Initiative, fetching any additional
 * information that may be required
 * @param item
 * @param auth
 * @returns
 */
async function convertItemToInitiative(item, requestOptions) {
    const model = await (0, fetchModelFromItem_1.fetchModelFromItem)(item, requestOptions);
    const mapper = new PropertyMapper_1.PropertyMapper((0, getPropertyMap_1.getPropertyMap)());
    const prj = mapper.storeToEntity(model, {});
    return (0, computeProps_1.computeProps)(model, prj, requestOptions);
}
/**
 * @private
 * Fetch Initiative specific enrichments
 * @param item
 * @param include
 * @param requestOptions
 * @returns
 */
async function enrichInitiativeSearchResult(item, include, requestOptions) {
    // Create the basic structure
    const result = {
        access: item.access,
        id: item.id,
        type: item.type,
        name: item.title,
        owner: item.owner,
        typeKeywords: item.typeKeywords,
        summary: item.snippet || item.description,
        createdDate: new Date(item.created),
        createdDateSource: "item.created",
        updatedDate: new Date(item.modified),
        updatedDateSource: "item.modified",
        family: (0, get_family_1.getFamily)(item.type),
        links: {
            self: "not-implemented",
            siteRelative: "not-implemented",
            thumbnail: "not-implemented",
            workspaceRelative: "not-implemented",
        },
        location: (0, internalContentUtils_1.deriveLocationFromItem)(item),
        rawResult: item,
    };
    // default includes
    const DEFAULTS = [];
    // merge includes
    include = [...DEFAULTS, ...include].filter(util_1.unique);
    // Parse the includes into a valid set of enrichments
    const specs = include.map(parseInclude_1.parseInclude);
    // Extract out the low-level enrichments needed
    const enrichments = (0, map_by_1.mapBy)("enrichment", specs).filter(util_1.unique);
    // fetch the enrichments
    let enriched = {};
    if (enrichments.length) {
        // TODO: Look into caching for the requests in fetchItemEnrichments
        enriched = await (0, _enrichments_1.fetchItemEnrichments)(item, enrichments, requestOptions);
    }
    // map the enriched props onto the result
    specs.forEach((spec) => {
        result[spec.prop] = (0, get_prop_1.getProp)(enriched, spec.path);
    });
    // Handle links
    // TODO: Link handling should be an enrichment
    result.links = (0, computeLinks_1.computeLinks)(item, requestOptions);
    return result;
}
// NOTE: even though I can't find any uses of
// this deprecated function in the codebase
// if you delete it, tests in the following files will fail
// but _only in node_, not in chrome, so go figure:
// - projects/fetch.test.ts
// - search/_internal/portalSearchItems.test.ts
/**
 * ** DEPRECATED: Please use the association methods directly.
 * This will be removed in the next breaking version **
 *
 * Related Projects are those that have the Initiative id in the
 * typekeywords but NOT in the catalog. We use this query to show
 * Projects which want to be associated but are not yet included in
 * the catalog
 * This is passed into the Gallery showing "Pending Projects"
 * @param initiative
 * @returns
 */
/* istanbul ignore next -- @preserve */
function getPendingProjectsQuery(initiative) {
    // get query that returns Hub Projects with the initiative keyword
    let query = (0, getTypeWithKeywordQuery_1.getTypeWithKeywordQuery)("Hub Project", `initiative|${initiative.id}`);
    // The the item scope from the catalog...
    const qry = (0, get_prop_1.getProp)(initiative, "catalog.scopes.item");
    // negate the scope, combine that with the base query
    query = (0, combineQueries_1.combineQueries)([query, (0, negateGroupPredicates_1.negateGroupPredicates)(qry)]);
    return query;
}
//# sourceMappingURL=HubInitiatives.js.map