"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.send = send;
const actions_core_1 = require("@segment/actions-core");
const constants_1 = require("./constants");
const hashing_utils_1 = require("../../../lib/hashing-utils");
async function send(request, payload, isBatch = false) {
    const url = isBatch ? constants_1.BATCH_URL : constants_1.URL;
    const msResponse = new actions_core_1.MultiStatusResponse();
    const indexToJsonItem = {};
    const json = payload.reduce((acc, p, index) => {
        const error = validate(p);
        if (error) {
            if (!isBatch) {
                throw new actions_core_1.PayloadValidationError(error);
            }
            msResponse.setErrorResponseAtIndex(index, {
                status: 400,
                errortype: 'PAYLOAD_VALIDATION_FAILED',
                errormessage: error,
                sent: payload
            });
        }
        else {
            const jsonItem = buildJSONItem(p);
            indexToJsonItem[index] = jsonItem;
            msResponse.setSuccessResponseAtIndex(index, {
                status: 200,
                sent: jsonItem,
                body: JSON.stringify(p)
            });
            acc.push(jsonItem);
        }
        return acc;
    }, []);
    if (json.length > 0) {
        try {
            await request(url, {
                method: 'POST',
                json: isBatch ? json : json[0]
            });
            if (isBatch) {
                return msResponse;
            }
        }
        catch (error) {
            if (!isBatch) {
                throw error;
            }
            payload.forEach((p, index) => {
                if (!msResponse.isErrorResponseAtIndex(index)) {
                    msResponse.setErrorResponseAtIndex(index, {
                        status: error.response?.status || 500,
                        errormessage: error.message,
                        sent: indexToJsonItem[index] || {},
                        body: JSON.stringify(p)
                    });
                }
            });
        }
    }
    if (isBatch) {
        return msResponse;
    }
}
function validate(payload) {
    const { device_info: { ios_advertising_id, android_advertising_id, ios_idfv, android_uuid } = {}, user_identities: { email, customerid, } = {}, rtid } = payload;
    if (!(email || customerid || rtid || ios_advertising_id || android_advertising_id || ios_idfv || android_uuid)) {
        return 'At least one of the following is required: iOS Advertising ID, Android Advertising ID, iOS ID for Vendor, Android UUID, Email, Customer ID, RTID.';
    }
}
function buildJSONItem(payload) {
    const { hashingConfiguration: { hashEmail, hashFirstName, hashLastName, hashMobile, hashBillingZipcode } = {}, device_info: { http_header_user_agent, ios_advertising_id, android_advertising_id, ios_idfv, android_uuid } = {}, user_identities: { email, customerid } = {}, user_attributes: { firstname, lastname, mobile, billingzipcode, dob, gender, ...restUserAttributes } = {}, ip, rtid } = payload;
    const device_info = {
        ...(http_header_user_agent ? { http_header_user_agent } : {}),
        ...(ios_advertising_id ? { ios_advertising_id } : {}),
        ...(android_advertising_id ? { android_advertising_id } : {}),
        ...(ios_idfv ? { ios_idfv } : {}),
        ...(android_uuid ? { android_uuid } : {})
    };
    const user_identities = {
        ...(email ? maybeHash(email, hashEmail, 'email', 'other', (value) => value.toLocaleLowerCase().trim()) : {}),
        ...(customerid ? { customerid } : {}),
        ...(rtid ? { other2: rtid } : {})
    };
    const audienceJSON = getAudienceJSON(payload);
    const eventJSON = getEventJSON(payload);
    const events = [
        ...(audienceJSON ? [audienceJSON] : []),
        ...(eventJSON ? [eventJSON] : [])
    ];
    const { audience_name, status } = audienceJSON?.data?.custom_attributes || {};
    const user_attributes = {
        ...(firstname ? maybeHash(firstname, hashFirstName, 'firstname', 'firstnamesha256', (value) => value.trim()) : {}),
        ...(lastname ? maybeHash(lastname, hashLastName, 'lastname', 'lastnamesha256', (value) => value.trim()) : {}),
        ...(mobile ? maybeHash(mobile, hashMobile, 'mobile', 'mobilesha256', (value) => value.trim()) : {}),
        ...(billingzipcode ? maybeHash(billingzipcode, hashBillingZipcode, 'billingzipcode', 'billingzipsha256', (value) => value.trim()) : {}),
        ...(dob ? { dob: new Date(dob).toISOString().slice(0, 10).replace(/-/g, '') } : {}),
        ...(gender === 'm' || gender === 'f' ? { gender } : {}),
        ...(restUserAttributes && Object.keys(restUserAttributes).length > 0 ? sanitize(restUserAttributes, ['boolean', 'string', 'number'], true) : {}),
        ...(audience_name && status ? { [`segment_${audience_name}`]: status === 'add' } : {})
    };
    const item = {
        environment: 'production',
        device_info,
        user_attributes,
        user_identities,
        ...(rtid ? { integration_attributes: { "1277": { passbackconversiontrackingid: rtid } } } : {}),
        ...(events && events.length > 0 ? { events } : {}),
        ...(ip ? { ip } : {})
    };
    return item;
}
function getAudienceJSON(payload) {
    const { eventDetails: { source_message_id, timestamp_unixtime_ms }, audienceDetails: { customAudienceName, customAudienceMembership } = {}, engageAudienceName, traitsOrProps, computationAction } = payload;
    const isEngageAudience = engageAudienceName && traitsOrProps && computationAction && typeof traitsOrProps[engageAudienceName] === 'boolean';
    const audienceName = isEngageAudience ? engageAudienceName : customAudienceName;
    if (!audienceName) {
        return undefined;
    }
    const membership = (() => {
        if (isEngageAudience) {
            const engageMembership = traitsOrProps[engageAudienceName];
            return typeof engageMembership === 'boolean' ? engageMembership : undefined;
        }
        else {
            return typeof customAudienceMembership === 'boolean' ? customAudienceMembership : undefined;
        }
    })();
    if (typeof membership !== 'boolean') {
        return undefined;
    }
    const audienceJSON = {
        event_type: "custom_event",
        data: {
            custom_event_type: "other",
            source_message_id,
            timestamp_unixtime_ms: new Date(timestamp_unixtime_ms).getTime(),
            event_name: "audiencemembershipupdate",
            custom_attributes: {
                audience_name: audienceName,
                status: membership ? 'add' : 'drop'
            }
        }
    };
    return audienceJSON;
}
function getEventJSON(payload) {
    const { eventDetails: { conversiontype, confirmationref, amount, currency, source_message_id, timestamp_unixtime_ms }, eventProperties, } = payload;
    if (!conversiontype) {
        return undefined;
    }
    const eventJSON = {
        event_type: "custom_event",
        data: {
            custom_event_type: "transaction",
            source_message_id,
            timestamp_unixtime_ms: new Date(timestamp_unixtime_ms).getTime(),
            event_name: "conversion",
            custom_attributes: {
                conversiontype,
                ...(confirmationref ? { confirmationref } : {}),
                ...(amount ? { amount } : {}),
                ...(currency ? { currency } : {}),
                ...sanitize(eventProperties, ['number', 'string', 'boolean'], false)
            }
        }
    };
    return eventJSON;
}
function sanitize(obj, allowedTypes, allowArrays) {
    if (!obj)
        return undefined;
    const result = {};
    Object.entries(obj).forEach(([key, value]) => {
        if (allowedTypes.includes(typeof value)) {
            result[key] = value;
        }
        else if (allowArrays && Array.isArray(value)) {
            const filtered = value.filter((v) => allowedTypes.includes(typeof v));
            if (filtered.length)
                result[key] = filtered;
        }
    });
    return result;
}
function maybeHash(value, shouldHash, key, hashedKey, cleaningFunction) {
    if (!value) {
        return {};
    }
    const isHashed = (0, hashing_utils_1.isAlreadyHashed)(value, 'sha256', 'hex');
    if (isHashed) {
        return {
            [hashedKey]: value
        };
    }
    else if (typeof shouldHash === 'boolean' && shouldHash) {
        const hashedValue = (0, hashing_utils_1.processHashing)(value, 'sha256', 'hex', cleaningFunction);
        return {
            [hashedKey]: hashedValue
        };
    }
    else {
        return { [key]: cleaningFunction ? cleaningFunction(value) : value };
    }
}
//# sourceMappingURL=functions.js.map