"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.send = send;
exports.failAllPayloads = failAllPayloads;
exports.getJSON = getJSON;
exports.getIds = getIds;
exports.getId = getId;
exports.handleError = handleError;
exports.sendRequest = sendRequest;
exports.getIdTypeName = getIdTypeName;
const actions_core_1 = require("@segment/actions-core");
const constants_1 = require("../constants");
const functions_1 = require("../functions");
async function send(request, payloads, settings, isBatch, audienceSettings, audienceMemberships) {
    const { segment_external_audience_id: audienceId } = payloads[0];
    const { endpoint } = settings;
    const { id_type } = (audienceSettings || {});
    const msResponse = new actions_core_1.MultiStatusResponse();
    if (!Array.isArray(audienceMemberships)) {
        return failAllPayloads(payloads, msResponse, isBatch, 'Audience membership details missing');
    }
    if (!id_type) {
        return failAllPayloads(payloads, msResponse, isBatch, 'ID Type must be specified in Audience Settings.');
    }
    const addMap = new Map();
    const deleteMap = new Map();
    payloads.forEach((payload, index) => {
        const membership = audienceMemberships[index];
        if (membership === true) {
            addMap.set(index, payload);
        }
        if (membership === false) {
            deleteMap.set(index, payload);
        }
        if (membership === undefined) {
            handleError(payload, msResponse, index, isBatch, "Audience Membership Details missing", 'PAYLOAD_VALIDATION_FAILED');
        }
    });
    const requests = [];
    if (addMap.size > 0) {
        const json = getJSON(addMap, id_type, audienceId, msResponse, 'ADD', isBatch);
        if (json) {
            requests.push(sendRequest(request, addMap, msResponse, json, id_type, endpoint, isBatch));
        }
    }
    if (deleteMap.size > 0) {
        const json = getJSON(deleteMap, id_type, audienceId, msResponse, 'REMOVE', isBatch);
        if (json) {
            requests.push(sendRequest(request, deleteMap, msResponse, json, id_type, endpoint, isBatch));
        }
    }
    if (requests.length === 0) {
        if (isBatch) {
            return msResponse;
        }
        throw new actions_core_1.PayloadValidationError("The payload is invalid and cannot be sent to Amplitude. Check that it contains the correct type of identifier");
    }
    await Promise.all(requests);
    if (isBatch) {
        return msResponse;
    }
}
function failAllPayloads(payloads, msResponse, isBatch, message) {
    payloads.forEach((payload, index) => {
        handleError(payload, msResponse, index, isBatch, message, 'PAYLOAD_VALIDATION_FAILED');
    });
    if (isBatch) {
        return msResponse;
    }
    throw new actions_core_1.PayloadValidationError(message);
}
function getJSON(map, id_type, audienceId, msResponse, operation, isBatch) {
    const ids = getIds(map, id_type, msResponse, isBatch);
    if (ids.length === 0) {
        return undefined;
    }
    const json = {
        cohort_id: audienceId,
        skip_invalid_ids: true,
        memberships: [{
                ids,
                id_type,
                operation
            }]
    };
    return json;
}
function getIds(map, id_type, msResponse, isBatch) {
    const idSet = new Set();
    for (const [index, payload] of map.entries()) {
        const id = getId(payload, id_type);
        if (id) {
            if (idSet.has(id)) {
                handleError(payload, msResponse, index, isBatch, `Duplicate ID ${id} of type ${getIdTypeName(id_type)} found in payload batch. The duplicate payload has been rejected. Each payload must have a unique ID for the specified ID Type.`, 'PAYLOAD_VALIDATION_FAILED');
            }
            else {
                idSet.add(id);
            }
        }
        else {
            handleError(payload, msResponse, index, isBatch, `No User Identifier of type ${getIdTypeName(id_type)} found in payload. Each payload must have a unique ID for the specified ID Type.`, 'PAYLOAD_VALIDATION_FAILED');
        }
    }
    return Array.from(idSet);
}
function getId(payload, id_type) {
    if (id_type === constants_1.ID_TYPES.BY_USER_ID) {
        return payload.user_id;
    }
    else if (id_type === constants_1.ID_TYPES.BY_AMP_ID) {
        return payload.amplitude_id;
    }
    return undefined;
}
function handleError(payload, msResponse, index, isBatch, errormessage, errortype, sent) {
    if (isBatch) {
        msResponse.setErrorResponseAtIndex(index, {
            status: 400,
            errortype,
            errormessage,
            body: payload,
            ...(sent && { sent })
        });
    }
    else {
        throw new actions_core_1.PayloadValidationError(errormessage);
    }
}
async function sendRequest(request, map, msResponse, json, id_type, endpoint, isBatch) {
    const url = (0, functions_1.getEndpointByRegion)('cohorts_membership', endpoint);
    const idTypeName = getIdTypeName(id_type);
    try {
        const response = await request(url, {
            method: 'POST',
            json
        });
        const skippedIds = new Set(response?.data?.memberships_result[0]?.skipped_ids || []);
        for (const [index, payload] of map.entries()) {
            const id = getId(payload, id_type);
            if (id && skippedIds.has(id)) {
                handleError(payload, msResponse, index, isBatch, `The user with ${idTypeName} ${id} was invalid and was not processed in the cohort update.`, 'UNKNOWN_ERROR');
            }
            else if (isBatch && !msResponse.getResponseAtIndex(index)) {
                msResponse.setSuccessResponseAtIndex(index, {
                    status: 200,
                    body: payload,
                    sent: { ...json, memberships: [{ ...json.memberships[0], ids: [id] }] }
                });
            }
        }
    }
    catch (err) {
        const { response: { data: { error: { error, message } = {} } = {} } = {} } = err;
        for (const [index, payload] of map.entries()) {
            const id = getId(payload, id_type);
            if (isBatch && msResponse.getResponseAtIndex(index)) {
                continue;
            }
            handleError(payload, msResponse, index, isBatch, `Request failed for payload with ID ${id} of type ${id_type} with error: ${error || 'UNKNOWN_ERROR'} and message: ${message || 'No message returned from Amplitude'}`, error || 'UNKNOWN_ERROR', { ...json, memberships: [{ ...json.memberships[0], ids: [id] }] });
        }
    }
}
function getIdTypeName(id_type) {
    return id_type === constants_1.ID_TYPES.BY_USER_ID ? 'User ID' : 'Amplitude ID';
}
//# sourceMappingURL=functions.js.map