import { getFamily } from "../content/get-family";
import { deriveLocationFromItem } from "../content/_internal/internalContentUtils";
import { fetchItemEnrichments } from "../items/_enrichments";
import { parseInclude } from "../search/_internal/parseInclude";
import { cloneObject, unique } from "../util";
import { constructSlug } from "../items/slugs";
import { PropertyMapper } from "../core/_internal/PropertyMapper";
import { getPropertyMap } from "./_internal/getPropertyMap";
import { computeProps } from "./_internal/computeProps";
import { removeItem } from "@esri/arcgis-rest-portal";
import { DEFAULT_PAGE, DEFAULT_PAGE_MODEL } from "./defaults";
import { ensureUniqueEntitySlug } from "../items/_internal/ensureUniqueEntitySlug";
import { computeLinks } from "./_internal/computeLinks";
import { fetchItem } from "../items/fetch";
import { createModel } from "../models/createModel";
import { fetchModelFromItem } from "../models/fetchModelFromItem";
import { getModel } from "../models/getModel";
import { updateModel } from "../models/updateModel";
import { getProp } from "../objects/get-prop";
import { mapBy } from "../utils/map-by";
/**
 * @private
 * Create a new Hub Page item
 *
 * Minimal properties are name and org
 *
 * @param partialPage
 * @param requestOptions
 */
export async function createPage(partialPage, requestOptions) {
    // merge incoming with the default
    // this expansion solves the typing somehow
    const page = Object.assign(Object.assign({}, DEFAULT_PAGE), partialPage);
    // ensure orgUrlKey is lowercase
    page.orgUrlKey = page.orgUrlKey.toLowerCase();
    // Create a slug from the title if one is not passed in
    if (!page.slug) {
        page.slug = constructSlug(page.name, page.orgUrlKey);
    }
    // Ensure slug is  unique
    await ensureUniqueEntitySlug(page, requestOptions);
    // Map page object onto a default page Model
    const mapper = new PropertyMapper(getPropertyMap());
    // create model from object, using the default model as a starting point
    let model = mapper.entityToStore(page, cloneObject(DEFAULT_PAGE_MODEL));
    // create the item
    model = await createModel(model, requestOptions);
    // map the model back into a IHubPage
    let newPage = mapper.storeToEntity(model, {});
    newPage = computeProps(model, newPage, requestOptions);
    // and return it
    return newPage;
}
/**
 * @private
 * Update a Hub Page
 * @param page
 * @param requestOptions
 */
export async function updatePage(page, requestOptions) {
    // verify that the slug is unique, excluding the current page
    await ensureUniqueEntitySlug(page, requestOptions);
    // get the backing item & data
    const model = await getModel(page.id, requestOptions);
    // create the PropertyMapper
    const mapper = new PropertyMapper(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(page, model);
    // update the backing item
    const updatedModel = await updateModel(modelToUpdate, requestOptions);
    // now map back into a page and return that
    let updatedPage = mapper.storeToEntity(updatedModel, page);
    updatedPage = computeProps(model, updatedPage, requestOptions);
    // the casting is needed because modelToObject returns a `Partial<T>`
    // where as this function returns a `T`
    return updatedPage;
}
/**
 * @private
 * Get a Hub Page by id or slug
 * @param identifier item id or slug
 * @param requestOptions
 */
export async function fetchPage(identifier, requestOptions) {
    const item = await fetchItem(identifier, requestOptions);
    return item ? convertItemToPage(item, requestOptions) : null;
}
/**
 * @internal
 * Convert an IModel for a Hub Page Item into an IHubPage
 * @param model
 * @param requestOptions
 * @returns
 */
export function convertModelToPage(model, requestOptions) {
    const mapper = new PropertyMapper(getPropertyMap());
    const prj = mapper.storeToEntity(model, {});
    return computeProps(model, prj, requestOptions);
}
/**
 * @private
 * Convert an Hub Page Item into a Hub Page, fetching any additional
 * information that may be required
 * @param item
 * @param auth
 * @returns
 */
export async function convertItemToPage(item, requestOptions) {
    const model = await fetchModelFromItem(item, requestOptions);
    // TODO: In the future we will handle the boundary fetching from resource
    return convertModelToPage(model, requestOptions);
}
/**
 * @private
 * Remove a Hub Page
 * @param id
 * @param requestOptions
 */
export async function deletePage(id, requestOptions) {
    const ro = Object.assign(Object.assign({}, requestOptions), { id });
    await removeItem(ro);
    return;
}
/**
 * Fetch Page specific Enrichments
 * @param item
 * @param include
 * @param requestOptions
 * @returns
 */
export async function enrichPageSearchResult(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,
        tags: item.tags,
        categories: item.categories,
        summary: item.snippet || item.description,
        createdDate: new Date(item.created),
        createdDateSource: "item.created",
        updatedDate: new Date(item.modified),
        updatedDateSource: "item.modified",
        family: getFamily(item.type),
        links: {
            self: "not-implemented",
            siteRelative: "not-implemented",
            thumbnail: "not-implemented",
        },
        location: deriveLocationFromItem(item),
        rawResult: item,
    };
    // default includes
    const DEFAULTS = [];
    // merge includes
    include = [...DEFAULTS, ...include].filter(unique);
    // Parse the includes into a valid set of enrichments
    const specs = include.map(parseInclude);
    // Extract out the low-level enrichments needed
    const enrichments = mapBy("enrichment", specs).filter(unique);
    // fetch the enrichments
    let enriched = {};
    if (enrichments.length) {
        // TODO: Look into caching for the requests in fetchItemEnrichments
        enriched = await fetchItemEnrichments(item, enrichments, requestOptions);
    }
    // map the enriched props onto the result
    specs.forEach((spec) => {
        result[spec.prop] = getProp(enriched, spec.path);
    });
    // Handle links
    result.links = computeLinks(item, requestOptions);
    return result;
}
//# sourceMappingURL=HubPages.js.map