"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.constructSlug = constructSlug;
exports.setSlugKeyword = setSlugKeyword;
exports.getItemBySlug = getItemBySlug;
exports.findItemsBySlug = findItemsBySlug;
exports.getUniqueSlug = getUniqueSlug;
const arcgis_rest_portal_1 = require("@esri/arcgis-rest-portal");
const slugify_1 = require("../utils/slugify");
const slugs_1 = require("./_internal/slugs");
const slugConverters_1 = require("./_internal/slugConverters");
/**
 * Create a slug, namespaced to an org and accounting for the 256 character limit
 * of individual typekeywords. Typically used to lookup items by a human readable name in urls
 *
 * @param title
 * @param orgKey
 * @returns
 */
function constructSlug(title, orgKey = "") {
    // allow some padding at the end for incrementing so we don't wind up w/ weird, inconsistent slugs
    // when the increment goes from single to multiple digits,
    // avoid producing the following when deduping:
    // slug|qa-pre-a-hub|some-really-really-...-really-long
    // slug|qa-pre-a-hub|some-really-really-...-really-lo-1
    // slug|qa-pre-a-hub|some-really-really-...-really-l-11
    // slug|qa-pre-a-hub|some-really-really-...-really-100
    const paddingEnd = 4;
    const slugified = (0, slugify_1.slugify)(title);
    if (!slugified) {
        // If slugify returns an empty string, return an empty string for the complete slug as well.
        // This is a rather strange edge case where in the process of auto-slugging a title for a Page or Event,
        // we end up with an invalid slug because the title did not include any valid characters for a slug [a-z0-9].
        return "";
    }
    return (0, slugs_1.truncateSlug)(slugified, orgKey.toLowerCase(), paddingEnd);
}
/**
 * Adds/Updates the slug typekeyword
 * Returns a new array of keywords
 *
 * @param typeKeywords A collection of typekeywords
 * @param slug The slug to add/update
 * @returns An updated collection of typekeywords
 */
function setSlugKeyword(typeKeywords, slug) {
    // remove slug entry from array
    const updatedTypekeywords = typeKeywords.filter((entry) => !entry.startsWith(`${slugs_1.TYPEKEYWORD_SLUG_PREFIX}|`));
    // now add it
    updatedTypekeywords.push([slugs_1.TYPEKEYWORD_SLUG_PREFIX, slug.toLowerCase()].join("|"));
    return updatedTypekeywords;
}
/**
 * Get an item by searching for items with a typeKeyword like `slug|{slug-value}`
 *
 * For example, if you pass a slug `"snow-map"` into this function, it will
 * search for items with `slug|snow-map` in it's typeKeywords array.
 * It also transforms uriSlugs into typeKeyword slugs by replacing `::` with `|`
 * Thus, passing a slug of `"myorg::snow-map"` would search for items with
 * `myorg|snow-map` in it's typeKeywords array.
 *
 * @param slug
 * @param requestOptions
 * @returns
 */
function getItemBySlug(slug, requestOptions) {
    const slugKeyword = (0, slugConverters_1.uriSlugToKeywordSlug)(slug);
    return findItemsBySlug({ slug: slugKeyword }, requestOptions).then((results) => {
        if (results.length) {
            // search results only include a subset of properties of the item, so
            // issue a subsequent call to getItem to get the full item details
            return (0, arcgis_rest_portal_1.getItem)(results[0].id, requestOptions);
        }
        else {
            return null;
        }
    });
}
/**
 * Find items by slug typeKeywords.
 *
 * Optional exclude parameter accepts the id of an item we expect to
 * have this particular slug. This is used during update calls
 * where we don't know if the slug specifically has been updated, but we
 * don't want a false-postive from the item we are updating
 *
 * @param slug
 * @param requestOptions
 * @returns
 */
async function findItemsBySlug(slugInfo, requestOptions) {
    if (!slugInfo.slug) {
        return [];
    }
    const filter = slugInfo.slug.startsWith(`${slugs_1.TYPEKEYWORD_SLUG_PREFIX}|`)
        ? slugInfo.slug
        : [slugs_1.TYPEKEYWORD_SLUG_PREFIX, slugInfo.slug].join("|");
    const opts = {
        filter: `typekeywords:"${filter}"`,
    };
    if (requestOptions.authentication) {
        opts.authentication = requestOptions.authentication;
    }
    else if (requestOptions.portal) {
        opts.portal = requestOptions.portal;
    }
    // We need to check for other items w/ a slug during
    // the update calls. For those scenarios we are interested
    // in any _other_ items which may have a specific slug
    // but not one specific item
    if (slugInfo.exclude) {
        opts.q = `NOT id:${slugInfo.exclude}`;
    }
    const response = await (0, arcgis_rest_portal_1.searchItems)(opts);
    return response.results;
}
/**
 * Given a slug, search for items using that slug, incrementing the slug name until
 * a unique value is found
 *
 * For example, if a slug of `"snow-map"` into this function and some item exists
 * with that slug, it would return `"snow-map-1"`.
 *
 * @param slug
 * @param requestOptions
 * @param step
 * @returns
 */
function getUniqueSlug(slugInfo, requestOptions, step = 0) {
    const combinedSlug = step ? [slugInfo.slug, step].join("-") : slugInfo.slug;
    return findItemsBySlug({ slug: combinedSlug, exclude: slugInfo.existingId }, requestOptions)
        .then((results) => !results.length
        ? combinedSlug
        : getUniqueSlug(slugInfo, requestOptions, step + 1))
        .catch((e) => {
        // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
        throw Error(`Error in getUniqueSlug ${e}`);
    });
}
//# sourceMappingURL=slugs.js.map