"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.WELL_KNOWN_EVENT_CATALOGS = exports.WELL_KNOWN_GROUP_CATALOGS = exports.WELL_KNOWN_ITEM_CATALOGS = void 0;
exports.dotifyString = dotifyString;
exports.getWellKnownCatalogs = getWellKnownCatalogs;
exports.getWellKnownCatalog = getWellKnownCatalog;
exports.getWellknownCollections = getWellknownCollections;
exports.getWellknownCollection = getWellknownCollection;
const get_family_1 = require("../content/get-family");
const buildCatalog_1 = require("./_internal/buildCatalog");
const get_prop_1 = require("../objects/get-prop");
const get_with_default_1 = require("../objects/get-with-default");
const getCOrgOrEOrgId_1 = require("./getCOrgOrEOrgId");
/** well-known item catalogs */
exports.WELL_KNOWN_ITEM_CATALOGS = [
    "myContent",
    "favorites",
    "organization",
    "world",
    "partners",
    "community",
    "livingAtlas",
];
/** well-known group catalogs */
exports.WELL_KNOWN_GROUP_CATALOGS = [
    "editGroups",
    "viewGroups",
    "allGroups",
    "myGroups",
    "orgGroups",
    "communityGroups",
    "publicGroups",
];
/** well-known event catalogs */
exports.WELL_KNOWN_EVENT_CATALOGS = [
    "myEvents",
    "orgEvents",
    "worldEvents",
];
/**
 * Check if i18nScope is defined and not ending with a ".", if so add a "." at the end.
 * e.g. if the i18nScope is 'project.edit', the path is `${i18nScope}catalog.organization`,
 * we will want "project.edit.catalog.organization" instead of "project.editcatalog.organization"
 * @param i18nScope
 * @returns i18nScope with a "." at the end if it is defined
 */
function dotifyString(i18nScope) {
    return i18nScope && i18nScope.slice(-1) !== "." ? `${i18nScope}.` : i18nScope;
}
/**
 * Helper function to build an array of well-known Catalogs
 * note: requested well-known Catalogs must be for the same
 * targetEntity type
 *
 * @param i18nScope Translation scope to be interpolated into the catalog
 * @param targetEntity The type of entity to query for
 * @param catalogNames Names of the catalogs requested
 * @param context contextual portal & auth information
 * @param opts optional IGetWellKnownCatalogOptions args
 */
function getWellKnownCatalogs(i18nScope, targetEntity, catalogNames, context, opts) {
    // 1. ensure the requested Catalogs are for the same targetEntity
    const validCatalogNames = {
        item: [...exports.WELL_KNOWN_ITEM_CATALOGS],
        group: [...exports.WELL_KNOWN_GROUP_CATALOGS],
        event: [...exports.WELL_KNOWN_EVENT_CATALOGS],
    }[targetEntity];
    if (catalogNames.some((name) => !validCatalogNames.includes(name))) {
        throw new Error(`Requested catalogs must be of the same targetEntity type: ${targetEntity}`);
    }
    // 2. build/return the well-known Catalogs
    return catalogNames.map((name) => {
        const catalog = getWellKnownCatalog(i18nScope, name, targetEntity, Object.assign(Object.assign({}, (opts || {})), { user: context.currentUser, context }));
        return catalog;
    });
}
/** Get a single catalog based on the catalog name, entity type and optional requests
 * @param i18nScope Translation scope to be interpolated into the catalog
 * @param name Name of the catalog requested
 * @param entityType
 * @param options An opitional IGetWellKnownCatalogOptions definition JSON object
 * @returns An IHubCatalog definition JSON object
 */
function getWellKnownCatalog(i18nScope, catalogName, entityType, options) {
    switch (entityType) {
        case "item":
            return getWellknownItemCatalog(i18nScope, catalogName, options);
        case "group":
            return getWellknownGroupCatalog(i18nScope, catalogName, options);
        case "event":
            return getWellknownEventCatalog(i18nScope, catalogName, options);
        default:
            throw new Error(`Wellknown catalog not implemented for "${entityType}"`);
    }
}
/**
 * Check if user is available in the passed options, throw an error if not
 * @param catalogName
 * @param options Options that contains user
 */
function validateUserExistence(catalogName, options) {
    if (!options || !options.user) {
        throw new Error(`User needed to get "${catalogName}" catalog`);
    }
}
/** TODO: On the next breaking change we need to pull context and user out of options
 * and make context a required parameter. User can be pulled out of context.
 */
/**
 * Get an ITEM catalog based on the name and optional requests
 * @param i18nScope Translation scope to be interpolated into the catalog
 * @param catalogName Name of the catalog requested
 * @param options An opitional IGetWellKnownCatalogOptions definition JSON object
 * @returns An ITEM IHubCatalog definition JSON object
 */
function getWellknownItemCatalog(i18nScope, catalogName, options) {
    i18nScope = dotifyString(i18nScope);
    let catalog;
    const additionalFilters = (0, get_prop_1.getProp)(options, "filters") || [];
    const context = (0, get_prop_1.getProp)(options, "context");
    const collections = getWellknownCollections(i18nScope, "item", options === null || options === void 0 ? void 0 : options.collectionNames);
    switch (catalogName) {
        case "myContent":
            validateUserExistence(catalogName, options);
            catalog = (0, buildCatalog_1.buildCatalog)(i18nScope, catalogName, [
                { predicates: [{ owner: options.user.username }] },
                ...additionalFilters,
            ], collections, "item");
            break;
        case "favorites":
            validateUserExistence(catalogName, options);
            catalog = (0, buildCatalog_1.buildCatalog)(i18nScope, catalogName, [
                { predicates: [{ group: options.user.favGroupId }] },
                ...additionalFilters,
            ], collections, "item");
            break;
        case "organization":
            validateUserExistence(catalogName, options);
            catalog = (0, buildCatalog_1.buildCatalog)(i18nScope, catalogName, [{ predicates: [{ orgid: options.user.orgId }] }, ...additionalFilters], collections, "item");
            break;
        case "partners":
            // Get trusted orgs that aren't the current user's org or the community org
            // eslint-disable-next-line no-case-declarations
            const trustedOrgIds = context.trustedOrgIds.filter((orgId) => {
                return (orgId !== context.currentUser.orgId &&
                    orgId !== (0, getCOrgOrEOrgId_1.getCOrgOrEOrgId)(context));
            });
            // only build the catalog if there are trusted orgs
            if (trustedOrgIds.length) {
                catalog = (0, buildCatalog_1.buildCatalog)(i18nScope, catalogName, [
                    {
                        predicates: [
                            {
                                orgid: trustedOrgIds,
                                searchUserAccess: "includeTrustedOrgs",
                            },
                        ],
                    },
                    ...additionalFilters,
                ], collections, "item");
            }
            break;
        case "community":
            // eslint-disable-next-line no-case-declarations
            const communityOrgId = (0, getCOrgOrEOrgId_1.getCOrgOrEOrgId)(context);
            // only build the catalog if there is a community org id
            if (communityOrgId) {
                catalog = (0, buildCatalog_1.buildCatalog)(i18nScope, catalogName, [{ predicates: [{ orgid: communityOrgId }] }, ...additionalFilters], collections, "item", 
                // If we're in a community org, use the community org name
                // as the catalog title
                context.isCommunityOrg
                    ? _getEOrgName(communityOrgId, context)
                    : undefined);
            }
            break;
        case "livingAtlas":
            validateUserExistence(catalogName, options);
            catalog = (0, buildCatalog_1.buildCatalog)(i18nScope, catalogName, [{ predicates: [{ owner: "Esri_LivingAtlas" }] }], collections, "item");
            break;
        case "world":
            catalog = (0, buildCatalog_1.buildCatalog)(i18nScope, catalogName, [
                { predicates: [{ type: { not: ["code attachment"] } }] },
                ...additionalFilters,
            ], collections, "item");
            break;
    }
    return catalog;
}
/**
 * If the user is in a community org, get the e-org name from the trusted org relationship
 * @param eOrgId E-org id
 * @param context IArcGISContext
 * @returns E-org name
 */
function _getEOrgName(eOrgId, context) {
    // extract the c-org / e-org relationship
    const communityTrustedOrgRelationship = context.trustedOrgs.find((org) => org.to.orgId === eOrgId);
    return communityTrustedOrgRelationship.to.name;
}
/**
 * Get a group catalog based on the name and optional requests
 * @param i18nScope Translation scope to be interpolated into the catalog
 * @param catalogName Name of the catalog requested
 * @param options An opitional IGetWellKnownCatalogOptions definition JSON object
 * @returns A group IHubCatalog definition JSON object
 */
function getWellknownGroupCatalog(i18nScope, catalogName, options) {
    let catalog;
    const { context, filters: additionalFilters = [] } = options || {};
    i18nScope = dotifyString(i18nScope);
    // because collections are needed in arcgis-hub-catalog and
    // "searchGroups" allows 'q: "*"', we use this as the collection
    const collections = [
        {
            targetEntity: "group",
            key: catalogName,
            label: catalogName,
            scope: {
                targetEntity: "group",
                filters: [
                    {
                        predicates: [{ q: "*" }],
                    },
                ],
            },
        },
    ];
    const idsOfUserAdminGroups = (0, get_with_default_1.getWithDefault)(context, "currentUser.groups", []).reduce((acc, group) => {
        // if you are updating this file, remove this comment and address the lint error
        // eslint-disable-next-line @typescript-eslint/no-unused-expressions
        group.userMembership.memberType === "admin" && acc.push(group.id);
        return acc;
    }, []);
    switch (catalogName) {
        case "editGroups":
            validateUserExistence(catalogName, options);
            catalog = (0, buildCatalog_1.buildCatalog)(i18nScope, catalogName, [
                { predicates: [{ capabilities: ["updateitemcontrol"] }] },
                ...additionalFilters,
            ], collections, "group");
            break;
        case "viewGroups":
            validateUserExistence(catalogName, options);
            catalog = (0, buildCatalog_1.buildCatalog)(i18nScope, catalogName, [
                { predicates: [{ capabilities: { not: ["updateitemcontrol"] } }] },
                ...additionalFilters,
            ], collections, "group");
            break;
        case "allGroups":
            validateUserExistence(catalogName, options);
            catalog = (0, buildCatalog_1.buildCatalog)(i18nScope, catalogName, [{ predicates: [{ capabilities: [""] }] }, ...additionalFilters], collections, "group");
            break;
        case "myGroups":
            validateUserExistence(catalogName, options);
            catalog = (0, buildCatalog_1.buildCatalog)(i18nScope, catalogName, [
                { predicates: [{ owner: (0, get_prop_1.getProp)(context, "currentUser.username") }] },
                ...additionalFilters,
            ], collections, "group");
            break;
        case "orgGroups":
            validateUserExistence(catalogName, options);
            catalog = (0, buildCatalog_1.buildCatalog)(i18nScope, catalogName, [
                {
                    predicates: [
                        {
                            orgid: (0, get_prop_1.getProp)(context, "currentUser.orgId"),
                            searchUserAccess: "groupMember",
                            searchUserName: (0, get_prop_1.getProp)(context, "currentUser.username"),
                            isviewonly: false,
                        },
                        {
                            orgid: (0, get_prop_1.getProp)(context, "currentUser.orgId"),
                            id: idsOfUserAdminGroups,
                        },
                    ],
                },
                ...additionalFilters,
            ], collections, "group");
            break;
        case "communityGroups":
            validateUserExistence(catalogName, options);
            catalog = (0, buildCatalog_1.buildCatalog)(i18nScope, catalogName, [
                {
                    predicates: [
                        {
                            orgid: (0, get_prop_1.getProp)(context, "communityOrgId"),
                            searchUserAccess: "groupMember",
                            searchUserName: (0, get_prop_1.getProp)(context, "currentUser.username"),
                            isviewonly: false,
                        },
                        {
                            orgid: (0, get_prop_1.getProp)(context, "communityOrgId"),
                            id: idsOfUserAdminGroups,
                        },
                    ],
                },
                ...additionalFilters,
            ], collections, "group");
            break;
        case "publicGroups":
            catalog = (0, buildCatalog_1.buildCatalog)(i18nScope, catalogName, [
                {
                    predicates: [
                        { orgid: { not: [(0, get_prop_1.getProp)(context, "currentUser.orgId")] } },
                    ],
                },
                ...additionalFilters,
            ], collections, "group");
            break;
    }
    return catalog;
}
/**
 * Build a well-known event catalog
 *
 * @param i18nScope Translation scope to be interpolated into the catalog
 * @param catalogName Name of the well-known catalog
 * @param options opitional IGetWellKnownCatalogOptions args
 */
function getWellknownEventCatalog(i18nScope, catalogName, options) {
    let catalog;
    const { context, filters: additionalFilters = [] } = options || {};
    i18nScope = dotifyString(i18nScope);
    // because collections are needed in arcgis-hub-catalog,
    // we add an "empty" collection
    const collections = [
        {
            key: catalogName,
            label: catalogName,
            targetEntity: "event",
            include: [],
            scope: {
                targetEntity: "event",
                filters: [{ predicates: [] }],
            },
        },
    ];
    switch (catalogName) {
        case "myEvents":
            validateUserExistence(catalogName, options);
            catalog = (0, buildCatalog_1.buildCatalog)(i18nScope, catalogName, [
                { predicates: [{ owner: (0, get_prop_1.getProp)(context, "currentUser.id") }] },
                ...additionalFilters,
            ], collections, "event");
            break;
        case "orgEvents":
            validateUserExistence(catalogName, options);
            catalog = (0, buildCatalog_1.buildCatalog)(i18nScope, catalogName, [
                { predicates: [{ orgid: (0, get_prop_1.getProp)(context, "currentUser.orgId") }] },
                ...additionalFilters,
            ], collections, "event");
            break;
        case "worldEvents":
            catalog = (0, buildCatalog_1.buildCatalog)(i18nScope, catalogName, [
                { predicates: [{ access: ["public", "private", "org"] }] },
                ...additionalFilters,
            ], collections, "event");
            break;
    }
    return catalog;
}
/**
 * Get a complete collections map to use to build a collections list
 * @param i18nScope
 * @param entityType
 * @returns an object that contains properties of all the collections
 */
function getAllCollectionsMap(i18nScope, entityType) {
    return {
        appAndMap: {
            key: "appAndMap",
            label: `{{${i18nScope}collection.appsAndMaps:translate}}`,
            targetEntity: entityType,
            include: [],
            scope: {
                targetEntity: entityType,
                filters: [
                    {
                        predicates: [
                            {
                                type: [...(0, get_family_1.getFamilyTypes)("app"), ...(0, get_family_1.getFamilyTypes)("map")],
                            },
                        ],
                    },
                ],
            },
        },
        dataset: {
            key: "dataset",
            label: `{{${i18nScope}collection.dataset:translate}}`,
            targetEntity: entityType,
            include: [],
            scope: {
                targetEntity: entityType,
                filters: [{ predicates: [{ type: (0, get_family_1.getFamilyTypes)("dataset") }] }],
            },
        },
        document: {
            key: "document",
            label: `{{${i18nScope}collection.documents:translate}}`,
            targetEntity: entityType,
            include: [],
            scope: {
                targetEntity: entityType,
                filters: [{ predicates: [{ type: (0, get_family_1.getFamilyTypes)("document") }] }],
            },
        },
        feedback: {
            key: "feedback",
            label: `{{${i18nScope}collection.feedback:translate}}`,
            targetEntity: entityType,
            include: [],
            scope: {
                targetEntity: entityType,
                filters: [{ predicates: [{ type: (0, get_family_1.getFamilyTypes)("feedback") }] }],
            },
        },
        site: {
            key: "site",
            label: `{{${i18nScope}collection.sites:translate}}`,
            targetEntity: entityType,
            include: [],
            scope: {
                targetEntity: entityType,
                filters: [
                    {
                        predicates: [
                            {
                                type: (0, get_family_1.getFamilyTypes)("site"),
                            },
                        ],
                    },
                ],
            },
        },
        template: {
            key: "template",
            label: `{{${i18nScope}collection.templates:translate}}`,
            targetEntity: entityType,
            include: [],
            scope: {
                targetEntity: entityType,
                filters: [
                    {
                        predicates: [
                            {
                                type: (0, get_family_1.getFamilyTypes)("template"),
                            },
                        ],
                    },
                ],
            },
        },
        project: {
            key: "project",
            label: `{{${i18nScope}collection.projects:translate}}`,
            targetEntity: entityType,
            include: [],
            scope: {
                targetEntity: entityType,
                filters: [
                    {
                        predicates: [
                            {
                                type: (0, get_family_1.getFamilyTypes)("project"),
                            },
                        ],
                    },
                ],
            },
        },
        // note: For now, this is not included in the default collection names.
        // It would need to be explicitly passed into getWellknownCollections
        // to be returned
        initiative: {
            key: "initiative",
            label: `{{${i18nScope}collection.initiatives:translate}}`,
            targetEntity: entityType,
            include: [],
            scope: {
                targetEntity: entityType,
                filters: [
                    {
                        predicates: [
                            {
                                type: (0, get_family_1.getFamilyTypes)("initiative"),
                                // only include v2 initiatives
                                typekeywords: ["hubInitiativeV2"],
                            },
                        ],
                    },
                ],
            },
        },
        // note: For now, this is not included in the default collection names.
        // It would need to be explicitly passed into getWellknownCollections
        // to be returned
        projectAndInitiative: {
            key: "projectAndInitiative",
            label: `{{${i18nScope}collection.projectsAndInitiatives:translate}}`,
            targetEntity: entityType,
            include: [],
            scope: {
                targetEntity: entityType,
                filters: [
                    {
                        operation: "OR",
                        predicates: [
                            {
                                type: (0, get_family_1.getFamilyTypes)("project"),
                            },
                            {
                                type: (0, get_family_1.getFamilyTypes)("initiative"),
                                // only include v2 initiatives
                                typekeywords: ["hubInitiativeV2"],
                            },
                        ],
                    },
                ],
            },
        },
    };
}
/**
 * Get a list of collection names we want to use to build the default collections if no specific collection names are passed
 * @returns a list of WellKnownCollection definition strings
 */
function getDefaultCollectionNames() {
    return ["appAndMap", "dataset", "document", "feedback", "site", "project"];
}
/**
 * Get a list of collections based on the entity type and an optional
 * list of collection names, will return a list of default collections if none passed
 * @param i18nScope Translation scope to be interpolated into the collections
 * @param entityType
 * @param collectionNames List of names of the requested collections, optional, if passed in,
 * only those collections will be returned
 * @returns A list of IHubCollection definition JSON objects
 */
function getWellknownCollections(i18nScope, entityType, collectionNames) {
    i18nScope = dotifyString(i18nScope);
    const allCollectionsMap = getAllCollectionsMap(i18nScope, entityType);
    const defaultCollectionNames = getDefaultCollectionNames();
    // Return a list of collections from the passed collection names or
    // return the default ones if not passed
    const names = (collectionNames === null || collectionNames === void 0 ? void 0 : collectionNames.length)
        ? collectionNames
        : defaultCollectionNames;
    return names.reduce((accum, name) => {
        if (allCollectionsMap[name]) {
            accum.push(allCollectionsMap[name]);
        }
        return accum;
    }, []);
}
/**
 * Get a single collection based on the collection name and entity type
 * @param i18nScope
 * @param entityType
 * @param collectionName Name of the collection requested
 * @returns An IHubCollection definition JSON object
 */
function getWellknownCollection(i18nScope, entityType, collectionName) {
    i18nScope = dotifyString(i18nScope);
    return getAllCollectionsMap(i18nScope, entityType)[collectionName];
}
//# sourceMappingURL=wellKnownCatalog.js.map