"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.LinkedInConversions = void 0;
const actions_core_1 = require("@segment/actions-core");
const constants_1 = require("../constants");
const hashing_utils_1 = require("../../../lib/hashing-utils");
function validate(payload, conversionTime) {
    const ninetyDaysAgo = Date.now() - 90 * 24 * 60 * 60 * 1000;
    if (conversionTime < ninetyDaysAgo) {
        throw new actions_core_1.PayloadValidationError('Timestamp should be within the past 90 days.');
    }
    if (!payload.email && !payload.linkedInUUID && !payload.acxiomID && !payload.oracleID) {
        throw new actions_core_1.PayloadValidationError('One of email or LinkedIn UUID or Axciom ID or Oracle ID is required.');
    }
}
function isNotEpochTimestampInMilliseconds(timestamp) {
    if (typeof timestamp === 'string' && !isNaN(Number(timestamp))) {
        const convertedTimestamp = Number(timestamp);
        const startDate = new Date('1970-01-01T00:00:00Z').getTime();
        const endDate = new Date('2100-01-01T00:00:00Z').getTime();
        if (Number.isSafeInteger(convertedTimestamp) && convertedTimestamp >= startDate && convertedTimestamp <= endDate) {
            return false;
        }
    }
    return true;
}
function convertToEpochMillis(timestamp) {
    const date = new Date(timestamp);
    return date.getTime();
}
class LinkedInConversions {
    constructor(request) {
        this.getConversionRule = async (adAccount, conversionRuleId) => {
            try {
                const { data } = await this.request(`${constants_1.BASE_URL}/conversions/${conversionRuleId}`, {
                    method: 'get',
                    searchParams: {
                        account: adAccount
                    }
                });
                return {
                    successMessage: `Using existing Conversion Rule: ${conversionRuleId} `,
                    savedData: {
                        id: conversionRuleId,
                        name: data.name || `No name returned for rule: ${conversionRuleId}`,
                        conversionType: data.type || `No type returned for rule: ${conversionRuleId}`,
                        attribution_type: data.attributionType || `No attribution type returned for rule: ${conversionRuleId}`,
                        post_click_attribution_window_size: data.postClickAttributionWindowSize || constants_1.DEFAULT_POST_CLICK_LOOKBACK_WINDOW,
                        view_through_attribution_window_size: data.viewThroughAttributionWindowSize || constants_1.DEFAULT_VIEW_THROUGH_LOOKBACK_WINDOW
                    }
                };
            }
            catch (e) {
                return {
                    error: {
                        message: `Failed to verify conversion rule: ${e?.message ?? JSON.stringify(e)}`,
                        code: 'CONVERSION_RULE_VERIFICATION_FAILURE'
                    }
                };
            }
        };
        this.createConversionRule = async (hookInputs) => {
            if (!hookInputs?.adAccountId) {
                return {
                    error: {
                        message: `Failed to create conversion rule: No Ad Account selected.`,
                        code: 'CONVERSION_RULE_CREATION_FAILURE'
                    }
                };
            }
            if (hookInputs?.conversionRuleId) {
                return this.getConversionRule(hookInputs.adAccountId, hookInputs?.conversionRuleId);
            }
            try {
                const { data } = await this.request(`${constants_1.BASE_URL}/conversions`, {
                    method: 'post',
                    json: {
                        name: hookInputs?.name,
                        account: hookInputs.adAccountId,
                        conversionMethod: 'CONVERSIONS_API',
                        postClickAttributionWindowSize: hookInputs?.post_click_attribution_window_size || constants_1.DEFAULT_POST_CLICK_LOOKBACK_WINDOW,
                        viewThroughAttributionWindowSize: hookInputs?.view_through_attribution_window_size || constants_1.DEFAULT_VIEW_THROUGH_LOOKBACK_WINDOW,
                        attributionType: hookInputs?.attribution_type,
                        type: hookInputs?.conversionType
                    }
                });
                return {
                    successMessage: `Conversion rule ${data.id} created successfully!`,
                    savedData: {
                        id: data.id,
                        name: data.name,
                        conversionType: data.type,
                        attribution_type: data.attributionType || 'UNKNOWN',
                        post_click_attribution_window_size: data.postClickAttributionWindowSize,
                        view_through_attribution_window_size: data.viewThroughAttributionWindowSize
                    }
                };
            }
            catch (e) {
                return {
                    error: {
                        message: `Failed to create conversion rule: ${e?.message ?? JSON.stringify(e)}`,
                        code: 'CONVERSION_RULE_CREATION_FAILURE'
                    }
                };
            }
        };
        this.updateConversionRule = async (hookInputs, hookOutputs) => {
            if (!hookOutputs) {
                return {
                    error: {
                        message: `Failed to update conversion rule: No existing rule to update.`,
                        code: 'CONVERSION_RULE_UPDATE_FAILURE'
                    }
                };
            }
            if (!hookInputs?.adAccountId) {
                return {
                    error: {
                        message: `Failed to update conversion rule: No Ad Account selected.`,
                        code: 'CONVERSION_RULE_UPDATE_FAILURE'
                    }
                };
            }
            if (hookInputs?.conversionRuleId) {
                return this.getConversionRule(hookInputs.adAccountId, hookInputs?.conversionRuleId);
            }
            const valuesChanged = this.conversionRuleValuesUpdated(hookInputs, hookOutputs);
            if (!valuesChanged) {
                if (!hookOutputs?.id || !hookOutputs?.name || !hookOutputs?.conversionType || !hookOutputs?.attribution_type) {
                    return {
                        error: {
                            message: `Failed to update conversion rule: Conversion rule values are not valid.`,
                            code: 'CONVERSION_RULE_UPDATE_FAILURE'
                        }
                    };
                }
                return {
                    successMessage: `No updates detected, using rule: ${hookOutputs.id}.`,
                    savedData: {
                        id: hookOutputs.id,
                        name: hookOutputs.name,
                        conversionType: hookOutputs.conversionType,
                        attribution_type: hookOutputs.attribution_type,
                        post_click_attribution_window_size: hookOutputs.post_click_attribution_window_size,
                        view_through_attribution_window_size: hookOutputs.view_through_attribution_window_size
                    }
                };
            }
            try {
                await this.request(`${constants_1.BASE_URL}/conversions/${hookOutputs.id}`, {
                    method: 'post',
                    searchParams: {
                        account: hookInputs.adAccountId
                    },
                    headers: {
                        'X-RestLi-Method': 'PARTIAL_UPDATE',
                        'Content-Type': 'application/json'
                    },
                    json: {
                        patch: {
                            $set: valuesChanged
                        }
                    }
                });
                return {
                    successMessage: `Conversion rule ${hookOutputs.id} updated successfully!`,
                    savedData: {
                        id: hookOutputs.id,
                        name: valuesChanged?.name || hookOutputs.name,
                        conversionType: valuesChanged?.type || hookOutputs.conversionType,
                        attribution_type: valuesChanged?.attributionType || hookOutputs.attribution_type,
                        post_click_attribution_window_size: valuesChanged?.postClickAttributionWindowSize || hookOutputs.post_click_attribution_window_size,
                        view_through_attribution_window_size: valuesChanged?.viewThroughAttributionWindowSize || hookOutputs.view_through_attribution_window_size
                    }
                };
            }
            catch (e) {
                return {
                    savedData: {
                        id: hookOutputs.id,
                        name: hookOutputs.name,
                        conversionType: hookOutputs.conversionType,
                        attribution_type: hookOutputs.attribution_type,
                        post_click_attribution_window_size: hookOutputs.post_click_attribution_window_size,
                        view_through_attribution_window_size: hookOutputs.view_through_attribution_window_size
                    },
                    error: {
                        message: `Failed to update conversion rule: ${e?.message ?? JSON.stringify(e)}`,
                        code: 'CONVERSION_RULE_UPDATE_FAILURE'
                    }
                };
            }
        };
        this.getAdAccounts = async () => {
            try {
                const allAdAccountsResponse = await this.request(`${constants_1.BASE_URL}/adAccounts`, {
                    method: 'GET',
                    searchParams: {
                        q: 'search'
                    }
                });
                const choices = allAdAccountsResponse.data.elements.map((item) => {
                    return {
                        label: item.name,
                        value: `urn:li:sponsoredAccount:${item.id}`
                    };
                });
                return {
                    choices
                };
            }
            catch (err) {
                return {
                    choices: [],
                    error: {
                        message: err.response?.data?.message ?? 'An error occurred while fetching ad accounts.',
                        code: err.response?.data?.code?.toString() ?? 'FETCH_AD_ACCOUNTS_ERROR'
                    }
                };
            }
        };
        this.getConversionRulesList = async (adAccountId) => {
            if (!adAccountId || !adAccountId.length) {
                return {
                    choices: [],
                    error: {
                        message: 'Please select Ad Account first to get list of Conversion Rules.',
                        code: 'FIELD_NOT_SELECTED'
                    }
                };
            }
            try {
                const response = [];
                const result = await this.request(`${constants_1.BASE_URL}/conversions`, {
                    method: 'GET',
                    skipResponseCloning: true,
                    searchParams: {
                        q: 'account',
                        account: adAccountId,
                        start: 0,
                        count: 100
                    }
                });
                result.data.elements.forEach((item) => {
                    if (item.enabled && item.conversionMethod === 'CONVERSIONS_API') {
                        response.push(item);
                    }
                });
                const choices = response?.map((item) => {
                    return {
                        label: item.name,
                        value: item.id
                    };
                });
                return {
                    choices
                };
            }
            catch (err) {
                return {
                    choices: [],
                    error: {
                        message: err.response?.data?.message ?? 'An error occurred while fetching conversion rules.',
                        code: err.response?.data?.code?.toString() ?? 'FETCH_CONVERSIONS_ERROR'
                    }
                };
            }
        };
        this.parseIdFromUrn = (urn) => {
            if (!urn) {
                return;
            }
            const parts = urn.split(':');
            const id = parts.pop();
            if (!id) {
                return;
            }
            return id;
        };
        this.getCampaignsList = async (adAccountUrn) => {
            const adAccountId = this.parseIdFromUrn(adAccountUrn);
            if (!adAccountId) {
                return {
                    choices: [],
                    error: {
                        message: 'Please select Ad Account first to get list of Conversion Rules.',
                        code: 'FIELD_NOT_SELECTED'
                    }
                };
            }
            try {
                const response = [];
                const result = await this.request(`${constants_1.BASE_URL}/adAccounts/${adAccountId}/adCampaigns?q=search&search=(status:(values:List(ACTIVE,DRAFT)))`, {
                    method: 'GET'
                });
                result.data.elements.forEach((item) => {
                    response.push(item);
                });
                const choices = response?.map((item) => {
                    return {
                        label: item.name,
                        value: item.id
                    };
                });
                return {
                    choices
                };
            }
            catch (err) {
                return {
                    choices: [],
                    error: {
                        message: err.response?.data?.message ?? 'An error occurred while fetching conversion rules.',
                        code: err.response?.data?.code?.toString() ?? 'FETCH_CONVERSIONS_ERROR'
                    }
                };
            }
        };
        this.normalizeEmail = (email) => {
            return email.toLowerCase();
        };
        this.buildUserIdsArray = (payload) => {
            const userIds = [];
            if (payload.email) {
                const hashedEmail = (0, hashing_utils_1.processHashing)(payload.email, 'sha256', 'hex', this.normalizeEmail);
                userIds.push({
                    idType: 'SHA256_EMAIL',
                    idValue: hashedEmail
                });
            }
            if (payload.linkedInUUID) {
                userIds.push({
                    idType: 'LINKEDIN_FIRST_PARTY_ADS_TRACKING_UUID',
                    idValue: payload.linkedInUUID
                });
            }
            if (payload.acxiomID) {
                userIds.push({
                    idType: 'AXCIOM_ID',
                    idValue: payload.acxiomID
                });
            }
            if (payload.oracleID) {
                userIds.push({
                    idType: 'ORACLE_MOAT_ID',
                    idValue: payload.oracleID
                });
            }
            return userIds;
        };
        this.conversionRuleValuesUpdated = (hookInputs, hookOutputs) => {
            const valuesChanged = {};
            if (hookInputs?.name && hookInputs?.name !== hookOutputs?.name) {
                valuesChanged.name = hookInputs?.name;
            }
            if (hookInputs?.conversionType && hookInputs?.conversionType !== hookOutputs?.conversionType) {
                valuesChanged.type = hookInputs?.conversionType;
            }
            if (hookInputs?.attribution_type && hookInputs?.attribution_type !== hookOutputs?.attribution_type) {
                valuesChanged.attributionType = hookInputs?.attribution_type;
            }
            if (hookInputs?.post_click_attribution_window_size &&
                hookInputs?.post_click_attribution_window_size !== hookOutputs?.post_click_attribution_window_size) {
                valuesChanged.postClickAttributionWindowSize = hookInputs?.post_click_attribution_window_size;
            }
            if (hookInputs?.view_through_attribution_window_size &&
                hookInputs?.view_through_attribution_window_size !== hookOutputs?.view_through_attribution_window_size) {
                valuesChanged.viewThroughAttributionWindowSize = hookInputs?.view_through_attribution_window_size;
            }
            return valuesChanged;
        };
        this.request = request;
    }
    setConversionRuleId(conversionRuleId) {
        this.conversionRuleId = conversionRuleId;
    }
    async getProfile() {
        return this.request(`${constants_1.BASE_URL}/me`, {
            method: 'GET'
        });
    }
    async streamConversionEvent(payload, conversionTime) {
        const userIds = this.buildUserIdsArray(payload);
        return this.request(`${constants_1.BASE_URL}/conversionEvents`, {
            method: 'POST',
            json: {
                conversion: `urn:lla:llaPartnerConversion:${this.conversionRuleId}`,
                conversionHappenedAt: conversionTime,
                conversionValue: payload.conversionValue,
                eventId: payload.eventId,
                user: {
                    userIds,
                    userInfo: payload.userInfo,
                    ...(Array.isArray(payload?.externalIds) && payload.externalIds.length > 0 ? { externalIds: [payload.externalIds[0]] } : {})
                }
            }
        });
    }
    async batchConversionAdd(payloads) {
        return this.request(`${constants_1.BASE_URL}/conversionEvents`, {
            method: 'post',
            headers: {
                'X-RestLi-Method': 'BATCH_CREATE'
            },
            json: {
                elements: [
                    ...payloads.map((payload) => {
                        const conversionTime = isNotEpochTimestampInMilliseconds(payload.conversionHappenedAt)
                            ? convertToEpochMillis(payload.conversionHappenedAt)
                            : Number(payload.conversionHappenedAt);
                        validate(payload, conversionTime);
                        const userIds = this.buildUserIdsArray(payload);
                        return {
                            conversion: `urn:lla:llaPartnerConversion:${this.conversionRuleId}`,
                            conversionHappenedAt: conversionTime,
                            conversionValue: payload.conversionValue,
                            eventId: payload.eventId,
                            user: {
                                userIds,
                                userInfo: payload.userInfo,
                                ...(Array.isArray(payload?.externalIds) && payload.externalIds.length > 0 ? { externalIds: [payload.externalIds[0]] } : {})
                            }
                        };
                    })
                ]
            }
        });
    }
    async bulkAssociateCampaignToConversion(campaignIds) {
        if (!campaignIds || campaignIds.length === 0) {
            return;
        }
        if (campaignIds.length === 1) {
            return this.associateCampignToConversion(campaignIds[0]);
        }
        const campaignConversions = new Map(campaignIds.map((campaignId) => {
            return [
                campaignId,
                `(campaign:${encodeURIComponent(`urn:li:sponsoredCampaign:${campaignId}`)},conversion:${encodeURIComponent(`urn:lla:llaPartnerConversion:${this.conversionRuleId})`)}`
            ];
        }));
        const entities = Object.fromEntries(Array.from(campaignConversions, ([id, value]) => [
            value,
            {
                campaign: `urn:li:sponsoredCampaign:${id}`,
                conversion: `urn:lla:llaPartnerConversion:${this.conversionRuleId}`
            }
        ]));
        const listString = Array.from(campaignConversions, ([_, value]) => value).join(',');
        return this.request(`${constants_1.BASE_URL}/campaignConversions?ids=List(${listString})`, {
            method: 'PUT',
            json: {
                entities
            }
        });
    }
    async associateCampignToConversion(campaignId) {
        return this.request(`${constants_1.BASE_URL}/campaignConversions/(campaign:urn%3Ali%3AsponsoredCampaign%3A${campaignId},conversion:urn%3Alla%3AllaPartnerConversion%3A${this.conversionRuleId})`, {
            method: 'PUT',
            body: JSON.stringify({
                campaign: `urn:li:sponsoredCampaign:${campaignId}`,
                conversion: `urn:lla:llaPartnerConversion:${this.conversionRuleId}`
            })
        });
    }
}
exports.LinkedInConversions = LinkedInConversions;
//# sourceMappingURL=index.js.map