"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const actions_core_1 = require("@segment/actions-core");
const api_1 = require("../api");
const isEmpty_1 = __importDefault(require("lodash/isEmpty"));
const action = {
    title: 'Sync Audience',
    description: 'Record custom events in Braze',
    defaultSubscription: 'event = "Audience Entered" or event = "Audience Exited"',
    fields: {
        external_id: {
            label: 'External User ID',
            description: 'The external_id serves as a unique user identifier for whom you are submitting data. This identifier should be the same as the one you set in the Braze SDK in order to avoid creating multiple profiles for the same user.',
            type: 'string',
            default: {
                '@path': '$.userId'
            }
        },
        user_alias: {
            label: 'User Alias Object',
            description: 'Alternate unique user identifier, this is required if External User ID or Device ID is not set. Refer [Braze Documentation](https://www.braze.com/docs/api/objects_filters/user_alias_object) for more details.',
            type: 'object',
            properties: {
                alias_name: {
                    label: 'Alias Name',
                    type: 'string',
                    required: true
                },
                alias_label: {
                    label: 'Alias Label',
                    type: 'string',
                    required: true
                }
            }
        },
        device_id: {
            label: 'Device ID',
            description: 'Device IDs can be used to add and remove only anonymous users to/from a cohort. However, users with an assigned User ID cannot use Device ID to sync to a cohort.',
            type: 'string'
        },
        cohort_id: {
            label: 'Cohort ID',
            description: 'The Cohort Identifier',
            type: 'string',
            unsafe_hidden: true,
            required: true,
            default: {
                '@path': '$.context.personas.computation_id'
            }
        },
        cohort_name: {
            label: 'Cohort Name',
            description: 'The name of Cohort',
            type: 'string',
            unsafe_hidden: true,
            required: true,
            default: {
                '@path': '$.context.personas.computation_key'
            }
        },
        enable_batching: {
            label: 'Enable Batching',
            description: 'Enable batching of requests to the Braze cohorts.',
            type: 'boolean',
            default: true
        },
        personas_audience_key: {
            label: 'Segment Engage Audience Key',
            description: 'The `audience_key` of the Engage audience you want to sync to Braze Cohorts. This value must be a hard-coded string variable, e.g. `personas_test_audience`, in order for batching to work properly.',
            type: 'string',
            required: true
        },
        event_properties: {
            label: 'Event Properties',
            description: 'Displays properties of the event to add/remove users to a cohort and the traits of the specific user',
            type: 'object',
            required: true,
            unsafe_hidden: true,
            default: {
                '@if': {
                    exists: { '@path': '$.properties' },
                    then: { '@path': '$.properties' },
                    else: { '@path': '$.traits' }
                }
            }
        },
        time: {
            label: 'Time',
            description: 'When the event occurred.',
            type: 'string',
            unsafe_hidden: true,
            required: true,
            default: {
                '@path': '$.timestamp'
            }
        },
        batch_keys: {
            label: 'Batch Keys',
            description: 'The keys to use for batching the events.',
            type: 'string',
            unsafe_hidden: true,
            default: ['cohort_name', 'cohort_id'],
            multiple: true,
            required: false
        }
    },
    perform: async (request, { settings, payload, stateContext }) => {
        return processPayload(request, settings, [payload], stateContext);
    },
    performBatch: async (request, { settings, payload, stateContext }) => {
        return processPayload(request, settings, payload, stateContext);
    }
};
async function processPayload(request, settings, payloads, stateContext) {
    validate(payloads);
    const syncAudiencesApiClient = new api_1.SyncAudiences(request, settings);
    const { cohort_name, cohort_id } = payloads[0];
    const cohortChanges = [];
    if (stateContext?.getRequestContext?.('cohort_name') != cohort_name) {
        await syncAudiencesApiClient.createCohort(settings, payloads[0]);
        stateContext?.setResponseContext?.(`cohort_name`, cohort_name, {});
    }
    const { addUsers, removeUsers } = extractUsers(payloads);
    const hasAddUsers = hasUsersToAddOrRemove(addUsers);
    const hasRemoveUsers = hasUsersToAddOrRemove(removeUsers);
    if (!hasAddUsers && !hasRemoveUsers) {
        return;
    }
    if (hasAddUsers) {
        cohortChanges.push(addUsers);
    }
    if (hasRemoveUsers) {
        cohortChanges.push(removeUsers);
    }
    return await syncAudiencesApiClient.batchUpdate(settings, cohort_id, cohortChanges);
}
function validate(payloads) {
    if (payloads[0].cohort_name !== payloads[0].personas_audience_key) {
        throw new actions_core_1.PayloadValidationError('The value of `personas computation key` and `personas_audience_key` must match.');
    }
}
function extractUsers(payloads) {
    payloads = payloads.sort((a, b) => new Date(b.time).getTime() - new Date(a.time).getTime());
    const addUsers = { user_ids: new Set(), device_ids: new Set(), aliases: new Map() };
    const removeUsers = {
        user_ids: new Set(),
        device_ids: new Set(),
        aliases: new Map(),
        should_remove: true
    };
    payloads.forEach((payload) => {
        const { event_properties, external_id, device_id, user_alias, personas_audience_key } = payload;
        const userEnteredOrRemoved = event_properties[`${personas_audience_key}`];
        const user = userEnteredOrRemoved ? addUsers : removeUsers;
        if (external_id && !addUsers.user_ids?.has(external_id) && !removeUsers.user_ids?.has(external_id)) {
            user?.user_ids?.add(external_id);
        }
        else if (device_id && !addUsers.device_ids?.has(device_id) && !removeUsers.device_ids?.has(device_id)) {
            user?.device_ids?.add(device_id);
        }
        else if (user_alias) {
            const aliasKey = `${user_alias.alias_name}:${user_alias.alias_label}`;
            if (!addUsers.aliases?.has(aliasKey) && !removeUsers.aliases?.has(aliasKey)) {
                user?.aliases?.set(aliasKey, user_alias);
            }
        }
    });
    return {
        addUsers: {
            user_ids: toMayBeArray(addUsers.user_ids),
            device_ids: toMayBeArray(addUsers.device_ids),
            aliases: transformAliases(addUsers.aliases)
        },
        removeUsers: {
            user_ids: toMayBeArray(removeUsers.user_ids),
            device_ids: toMayBeArray(removeUsers.device_ids),
            aliases: transformAliases(removeUsers.aliases),
            should_remove: removeUsers.should_remove
        }
    };
}
function transformAliases(aliases) {
    if (!aliases)
        return undefined;
    return Array.from(aliases.values()).map((alias) => ({
        alias_name: alias.alias_name,
        alias_label: alias.alias_label
    }));
}
function toMayBeArray(set) {
    return set ? Array.from(set) : undefined;
}
function hasUsersToAddOrRemove(user) {
    return !((0, isEmpty_1.default)(user?.user_ids) && (0, isEmpty_1.default)(user?.device_ids) && (0, isEmpty_1.default)(user?.aliases));
}
exports.default = action;
//# sourceMappingURL=index.js.map