"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getAvailableToRequestEntitiesQuery = void 0;
const getTypeFromEntity_1 = require("../core/getTypeFromEntity");
const getAssociationHierarchy_1 = require("./internal/getAssociationHierarchy");
const isAssociationSupported_1 = require("./internal/isAssociationSupported");
const get_prop_1 = require("../objects/get-prop");
const getTypesFromEntityType_1 = require("../core/getTypesFromEntityType");
const getIdsFromKeywords_1 = require("./internal/getIdsFromKeywords");
const getTypeByNotIdsQuery_1 = require("./internal/getTypeByNotIdsQuery");
const negateGroupPredicates_1 = require("../search/negateGroupPredicates");
const getTypeByIdsQuery_1 = require("./internal/getTypeByIdsQuery");
const combineQueries_1 = require("../search/combineQueries");
/**
 * An entity can send an "outgoing" request to associate
 * itself with another entity. The following query returns
 * a set of entities that the requesting entity can still
 * request:
 *
 * from a parent perspective: returns a set of children
 * that are NOT "included" in the parent's association group
 *
 * from a child perspective: returns a set of parents that
 * the child does not "reference" with via a typeKeyword of
 * the form ref|<parentType>|<parentID>
 *
 * @param entity - entity requesting association
 * @param associationType - type of entity the requesting entity wants to associate with
 * @param context - contextual auth and portal information
 * @returns {IQuery}
 */
const getAvailableToRequestEntitiesQuery = (entity, associationType) => {
    let query;
    const entityType = (0, getTypeFromEntity_1.getTypeFromEntity)(entity);
    const isSupported = (0, isAssociationSupported_1.isAssociationSupported)(entityType, associationType);
    if (!isSupported) {
        throw new Error(`getAvailableToRequestEntitiesQuery: Association between ${entityType} and ${associationType} is not supported.`);
    }
    const associationHierarchy = (0, getAssociationHierarchy_1.getAssociationHierarchy)(entityType);
    const isParent = associationHierarchy.children.includes(associationType);
    if (isParent) {
        /** 1. build query that returns child entities */
        const childType = (0, getTypesFromEntityType_1.getTypesFromEntityType)(associationType);
        const childTypeQuery = (0, getTypeByIdsQuery_1.getTypeByIdsQuery)(childType, []);
        /**
         * 2. grab the parent's association query and negate
         * the group predicate
         */
        const notIncludedQuery = (0, negateGroupPredicates_1.negateGroupPredicates)((0, get_prop_1.getProp)(entity, "associations.rules.query"));
        /** 3. combine queries - will remove null/undefined entries */
        query = (0, combineQueries_1.combineQueries)([notIncludedQuery, childTypeQuery]);
    }
    else {
        /**
         * 1. iterate over the child's typeKeywords and grab the parent
         * ids it references (typeKeyword = <associationType>|<id>)
         */
        const ids = (0, getIdsFromKeywords_1.getIdsFromKeywords)(entity, associationType);
        /**
         * 2. build query that returns parent entities NOT
         * "referenced" by the child
         */
        const type = (0, getTypesFromEntityType_1.getTypesFromEntityType)(associationType);
        query = (0, getTypeByNotIdsQuery_1.getTypeByNotIdsQuery)(type, ids);
    }
    return query;
};
exports.getAvailableToRequestEntitiesQuery = getAvailableToRequestEntitiesQuery;
//# sourceMappingURL=getAvailableToRequestEntitiesQuery.js.map