"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getAsyncResponse = exports.sendDebugMessageToSegmentSource = exports.upsertListMembers = exports.sendCustomTraits = exports.stringifyObject = exports.getUserDataFieldNames = exports.validateListMemberPayload = exports.shouldRetry = exports.testConditionsToRetry = exports.getRateLimits = void 0;
const actions_core_1 = require("@segment/actions-core");
const upsertListMembersWaitInterval = 150;
const getAsyncResponseWaitInterval = 60;
const getRateLimits = async (request, settings) => {
    const endpoint = new URL('/rest/api/ratelimit', settings.baseUrl);
    return request(endpoint.href, {
        method: 'GET',
        skipResponseCloning: true
    });
};
exports.getRateLimits = getRateLimits;
const testConditionsToRetry = ({ timestamp, statsContext, retry }) => {
    const statsClient = statsContext?.statsClient;
    const statsTag = statsContext?.tags;
    if (retry !== undefined && retry > 0 && (0, exports.shouldRetry)(timestamp, retry)) {
        if (statsClient && statsTag) {
            statsClient?.incr('responsysShouldRetryTRUE', 1, statsTag);
        }
        throw new actions_core_1.RetryableError('Event timestamp is within the retry window. Artificial delay to retry this event.', 429);
    }
    else {
        if (statsClient && statsTag) {
            statsClient?.incr('responsysShouldRetryFALSE', 1, statsTag);
        }
    }
};
exports.testConditionsToRetry = testConditionsToRetry;
const shouldRetry = (timestamp, retry) => {
    return (new Date().getTime() - new Date(timestamp).getTime()) / 1000 < retry;
};
exports.shouldRetry = shouldRetry;
const validateListMemberPayload = ({ EMAIL_ADDRESS_, RIID_, CUSTOMER_ID_ }) => {
    if (!EMAIL_ADDRESS_ && !RIID_ && !CUSTOMER_ID_) {
        throw new actions_core_1.PayloadValidationError('At least one of the following fields is required: Email Address, RIID, or Customer ID');
    }
};
exports.validateListMemberPayload = validateListMemberPayload;
const getUserDataFieldNames = (data) => {
    return Object.keys(data.rawMapping.userData);
};
exports.getUserDataFieldNames = getUserDataFieldNames;
const stringifyObject = (obj) => {
    const stringifiedObj = {};
    for (const key in obj) {
        stringifiedObj[key] = typeof obj[key] !== 'string' ? JSON.stringify(obj[key]) : obj[key];
    }
    return stringifiedObj;
};
exports.stringifyObject = stringifyObject;
const sendCustomTraits = async (request, payload, settings, userDataFieldNames, isAudience = false) => {
    let userDataArray;
    if (isAudience) {
        const audiencePayloads = payload;
        userDataArray = audiencePayloads.map((obj) => {
            const audienceKeyUppercase = obj.computation_key.toUpperCase();
            const audienceTraitValue = { [audienceKeyUppercase]: obj.traits_or_props[obj.computation_key] };
            if (!userDataFieldNames.includes(audienceKeyUppercase)) {
                userDataFieldNames.push(audienceKeyUppercase);
            }
            return {
                ...(obj.stringify ? (0, exports.stringifyObject)(obj.userData) : obj.userData),
                ...(obj.stringify ? (0, exports.stringifyObject)(audienceTraitValue) : audienceTraitValue)
            };
        });
    }
    else {
        const customTraitsPayloads = payload;
        userDataArray = customTraitsPayloads.map((obj) => (obj.stringify ? (0, exports.stringifyObject)(obj.userData) : obj.userData));
    }
    const records = userDataArray.map((userData) => {
        return userDataFieldNames.map((fieldName) => {
            return userData && fieldName in userData
                ? userData[fieldName]
                : '';
        });
    });
    const recordData = {
        fieldNames: userDataFieldNames.map((field) => field.toUpperCase()),
        records,
        mapTemplateName: ''
    };
    const requestBody = {
        recordData,
        insertOnNoMatch: settings.insertOnNoMatch,
        updateOnMatch: settings.updateOnMatch,
        matchColumnName1: settings.matchColumnName1,
        matchColumnName2: settings.matchColumnName2 || ''
    };
    const path = `/rest/asyncApi/v1.3/lists/${settings.profileListName}/listExtensions/${settings.profileExtensionTable}/members`;
    const endpoint = new URL(path, settings.baseUrl);
    const response = await request(endpoint.href, {
        method: 'POST',
        body: JSON.stringify(requestBody)
    });
    await (0, exports.sendDebugMessageToSegmentSource)(request, requestBody, response, settings);
    return response;
};
exports.sendCustomTraits = sendCustomTraits;
const upsertListMembers = async (request, authTokens, payload, settings, usingAsyncApi = true) => {
    const userDataArray = payload.map((obj) => (obj.stringify ? (0, exports.stringifyObject)(obj.userData) : obj.userData));
    const recordSets = {};
    for (const item of userDataArray) {
        const recordSetKey = Object.keys(item).join(',');
        const record = [];
        for (const fieldName of Object.keys(item)) {
            if (![
                'EMAIL_ADDRESS_',
                'EMAIL_MD5_HASH_',
                'EMAIL_SHA256_HASH_',
                'RIID_',
                'CUSTOMER_ID_',
                'MOBILE_NUMBER_'
            ].includes(fieldName)) {
                continue;
            }
            record.push(item[fieldName]);
        }
        if (recordSetKey in recordSets) {
            recordSets[recordSetKey].push(record);
        }
        else {
            recordSets[recordSetKey] = [record];
        }
    }
    const responses = [];
    for (const [recordSetKey, records] of Object.entries(recordSets)) {
        for (let i = 0; i < records.length; i += 200) {
            const chunk = records.slice(i, i + 200);
            const recordData = {
                fieldNames: recordSetKey.split(',').map((field) => field.toUpperCase()),
                records: chunk,
                mapTemplateName: ''
            };
            const mergeRule = {
                htmlValue: settings.htmlValue,
                optinValue: settings.optinValue,
                textValue: settings.textValue,
                insertOnNoMatch: settings.insertOnNoMatch || false,
                updateOnMatch: settings.updateOnMatch,
                matchColumnName1: settings.matchColumnName1 + '_',
                matchOperator: settings.matchOperator,
                optoutValue: settings.optoutValue,
                rejectRecordIfChannelEmpty: settings.rejectRecordIfChannelEmpty,
                defaultPermissionStatus: payload[0].default_permission_status || settings.defaultPermissionStatus
            };
            if (settings.matchColumnName2) {
                mergeRule.matchColumnName2 = settings.matchColumnName2 + '_';
            }
            const requestBody = {
                recordData,
                mergeRule
            };
            const path = `/rest/${usingAsyncApi ? 'asyncApi' : 'api'}/v1.3/lists/${settings.profileListName}/members`;
            const endpoint = new URL(path, settings.baseUrl);
            const headers = {
                headers: {
                    authorization: `${authTokens.accessToken}`,
                    'Content-Type': 'application/json'
                }
            };
            await new Promise((resolve) => setTimeout(resolve, upsertListMembersWaitInterval));
            const secondRequest = (0, actions_core_1.createRequestClient)(headers);
            const response = await secondRequest(endpoint.href, {
                method: 'POST',
                body: JSON.stringify(requestBody)
            });
            if (usingAsyncApi) {
                const requestId = response.data.requestId;
                const asyncResponse = await (0, exports.getAsyncResponse)(requestId, authTokens, settings);
                await (0, exports.sendDebugMessageToSegmentSource)(request, requestBody, asyncResponse, settings);
                responses.push(asyncResponse);
            }
            else {
                await (0, exports.sendDebugMessageToSegmentSource)(request, requestBody, response, settings);
                responses.push(response);
            }
        }
    }
    return responses;
};
exports.upsertListMembers = upsertListMembers;
const sendDebugMessageToSegmentSource = async (request, requestBody, response, settings) => {
    const segmentWriteKeyRegion = settings.segmentWriteKeyRegion || 'US';
    if (settings.segmentWriteKey) {
        try {
            const body = response.data;
            await request(segmentWriteKeyRegion === 'EU'
                ? 'https://events.eu1.segmentapis.com/v1/track'
                : 'https://api.segment.io/v1/track', {
                method: 'POST',
                headers: {
                    Authorization: 'Basic ' + Buffer.from(settings.segmentWriteKey + ': ').toString('base64'),
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({
                    type: 'track',
                    event: 'Responsys Response Message Received',
                    properties: {
                        body,
                        responsysRequest: {
                            ...requestBody
                        },
                        recordCount: requestBody.recordData.records.length
                    },
                    anonymousId: '__responsys__API__response__'
                })
            });
        }
        catch (error) {
        }
    }
};
exports.sendDebugMessageToSegmentSource = sendDebugMessageToSegmentSource;
const getAsyncResponse = async (requestId, authTokens, settings) => {
    const headers = {
        headers: {
            authorization: `${authTokens.accessToken}`,
            'Content-Type': 'application/json'
        }
    };
    const operationResponseEndpoint = new URL(`/rest/asyncApi/v1.3/requests/${requestId}`, settings.baseUrl);
    const request = (0, actions_core_1.createRequestClient)(headers);
    await new Promise((resolve) => setTimeout(resolve, getAsyncResponseWaitInterval));
    const asyncResponse = await request(operationResponseEndpoint.href, {
        method: 'GET',
        skipResponseCloning: true
    });
    return asyncResponse;
};
exports.getAsyncResponse = getAsyncResponse;
//# sourceMappingURL=utils.js.map