"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.portalSearchItems = portalSearchItems;
exports.portalSearchItemsAsItems = portalSearchItemsAsItems;
exports.itemToSearchResult = itemToSearchResult;
const arcgis_rest_portal_1 = require("@esri/arcgis-rest-portal");
const serializeQueryForPortal_1 = require("../serializeQueryForPortal");
const HubPages_1 = require("../../pages/HubPages");
const HubInitiatives_1 = require("../../initiatives/HubInitiatives");
const fetch_1 = require("../../templates/fetch");
const utils_1 = require("../utils");
const getNextPortalCallback_1 = require("./commonHelpers/getNextPortalCallback");
const portalSearchUtils_1 = require("./portalSearchUtils");
const HubError_1 = require("../../HubError");
const search_1 = require("../../content/search");
const fetch_2 = require("../../projects/fetch");
const HubSites_1 = require("../../sites/HubSites");
/**
 * @internal
 * Portal Search Implementation for Items returning IHubSearchResults
 * @param query
 * @param options
 * @returns
 */
async function portalSearchItems(query, options) {
    const queryWithDefaultPredicates = (0, utils_1.addDefaultItemSearchPredicates)(query);
    const so = processSearchParams(options, queryWithDefaultPredicates);
    return searchPortalAsHubSearchResult(so);
}
/**
 * @internal
 * Portal Search for Items using IQuery and IHubSearchOptions
 * @param query
 * @param options
 * @returns
 */
function portalSearchItemsAsItems(query, options) {
    const so = processSearchParams(options, query);
    return searchPortalAsItem(so);
}
/**
 * Common preprocessing for search options and the query
 * @param options
 * @param query
 * @returns
 */
function processSearchParams(options, query) {
    var _a;
    if (!options.requestOptions) {
        throw new HubError_1.default("portalSearchItems", "options.requestOptions is required.");
    }
    const updatedQuery = (0, utils_1.expandPortalQuery)(query);
    // Serialize the all the groups for portal
    const so = (0, serializeQueryForPortal_1.serializeQueryForPortal)(updatedQuery);
    // Array of properties we want to copy from IHubSearchOptions to the ISearchOptions
    const props = [
        "num",
        "sortField",
        "sortOrder",
        "include",
        "start",
        "httpMethod",
        "requestOptions", // although requestOptions is not needed on ISearchOption we send it through so downstream fns have access to it
    ];
    // copy the props over
    props.forEach((prop) => {
        if (Object.prototype.hasOwnProperty.call(options, prop)) {
            so[prop] = options[prop];
        }
    });
    if (options.requestOptions.authentication) {
        so.authentication = options.requestOptions.authentication;
    }
    else {
        so.portal = options.requestOptions.portal;
    }
    // Aggregations
    if ((_a = options.aggFields) === null || _a === void 0 ? void 0 : _a.length) {
        so.countFields = options.aggFields.join(",");
        so.countSize =
            options.aggLimit ||
                /* istanbul ignore next @preserve */
                10;
    }
    return so;
}
/**
 * Internal portal search, which just returns IItems witn no conversion
 * Due to typescript complexity when adding multiple returns types to a function
 * it is simpler to have two functions that do the almost the same thing.
 * @param searchOptions
 * @returns
 */
async function searchPortalAsItem(searchOptions) {
    // Execute portal search
    const resp = await (0, arcgis_rest_portal_1.searchItems)(searchOptions);
    // convert portal  aggregations into hub aggregations
    const aggregations = (0, portalSearchUtils_1.convertPortalAggregations)(resp);
    // Construct the return
    return {
        total: resp.total,
        results: resp.results,
        aggregations,
        hasNext: resp.nextStart > -1,
        next: (0, getNextPortalCallback_1.getNextPortalCallback)(searchOptions, resp.nextStart, resp.total, searchPortalAsItem),
        executedQuerySize: (0, utils_1.getKilobyteSizeOfQuery)(searchOptions.q),
    };
}
/**
 * Internal portal search, which then converts `IItem`s to `IHubSearchResult`s
 * handling enrichments & includes along the way
 *
 * @param searchOptions
 * @returns
 */
async function searchPortalAsHubSearchResult(searchOptions) {
    // Execute portal search
    const resp = await (0, arcgis_rest_portal_1.searchItems)(searchOptions);
    // create mappable fn that will handle the includes
    const fn = (item) => {
        return itemToSearchResult(item, searchOptions.include, searchOptions.requestOptions);
    };
    // map over results
    const results = await Promise.all(resp.results.map(fn));
    // convert portal  aggregations into hub aggregations
    const aggregations = (0, portalSearchUtils_1.convertPortalAggregations)(resp);
    // Construct the return
    return {
        total: resp.total,
        results,
        aggregations,
        hasNext: resp.nextStart > -1,
        next: (0, getNextPortalCallback_1.getNextPortalCallback)(searchOptions, resp.nextStart, resp.total, searchPortalAsHubSearchResult),
        executedQuerySize: (0, utils_1.getKilobyteSizeOfQuery)(searchOptions.q),
    };
}
/**
 * Convert an `IItem` to a `IHubSearchResult`
 * Fetches the enrichments, and attaches them as directed in the `include` list
 * @param item
 * @param includes
 * @param requestOptions
 * @returns
 */
async function itemToSearchResult(item, includes = [], requestOptions) {
    // based on the type, we delegate to type-specific functions
    // this allows each type to apply "default" enrichments
    let fn = search_1.enrichContentSearchResult;
    switch (item.type) {
        case "Hub Site Application":
        case "Site Application":
            fn = HubSites_1.enrichSiteSearchResult;
            break;
        case "Hub Page":
        case "Site Page":
            fn = HubPages_1.enrichPageSearchResult;
            break;
        case "Hub Project":
            fn = fetch_2.enrichProjectSearchResult;
            break;
        case "Hub Initiative":
            fn = HubInitiatives_1.enrichInitiativeSearchResult;
            break;
        case "Solution":
            fn = fetch_1.enrichTemplateSearchResult;
            break;
        // handle old hub sites
        case "Web Mapping Application":
            if (item.typeKeywords.includes("hubSite")) {
                fn = HubSites_1.enrichSiteSearchResult;
            }
            break;
        case "Image":
            // same as content but includes fallback for thumbnail
            fn = search_1.enrichImageSearchResult;
            break;
    }
    return fn(item, includes, requestOptions);
}
//# sourceMappingURL=portalSearchItems.js.map