"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const config_1 = require("../config");
const actions_core_1 = require("@segment/actions-core");
const functions_1 = require("../functions");
const properties_1 = require("../properties");
const action = {
    title: 'Upsert Profile',
    description: 'Upsert user profile.',
    defaultSubscription: 'type = "identify"',
    fields: {
        email: {
            label: 'Email',
            description: `Individual's email address. One of External ID, Phone Number and Email required.`,
            type: 'string',
            format: 'email',
            default: { '@path': '$.traits.email' }
        },
        enable_batching: {
            type: 'boolean',
            label: 'Batch Data to Klaviyo',
            description: 'When enabled, the action will use the klaviyo batch API.'
        },
        phone_number: {
            label: 'Phone Number',
            description: `Individual's phone number in E.164 format. If SMS is not enabled and if you use Phone Number as identifier, then you have to provide one of Email or External ID.`,
            type: 'string',
            default: { '@path': '$.context.traits.phone' }
        },
        country_code: {
            ...properties_1.country_code
        },
        external_id: {
            label: 'External ID',
            description: `A unique identifier used by customers to associate Klaviyo profiles with profiles in an external system. One of External ID, Phone Number and Email required.`,
            type: 'string'
        },
        first_name: {
            label: 'First Name',
            description: `Individual's first name.`,
            type: 'string',
            default: { '@path': '$.traits.firstName' }
        },
        last_name: {
            label: 'Last Name',
            description: `Individual's last name.`,
            type: 'string',
            default: { '@path': '$.traits.lastName' }
        },
        organization: {
            label: 'Organization',
            description: `Name of the company or organization within the company for whom the individual works.`,
            type: 'string',
            default: { '@path': '$.traits.company.name' }
        },
        title: {
            label: 'Title',
            description: `Individual's job title.`,
            type: 'string',
            default: { '@path': '$.traits.title' }
        },
        image: {
            label: 'Image',
            description: `URL pointing to the location of a profile image.`,
            type: 'string',
            default: { '@path': '$.traits.avatar' }
        },
        location: {
            label: 'Location',
            description: `Individual's address.`,
            type: 'object',
            properties: {
                address1: {
                    label: 'Address 1',
                    type: 'string',
                    allowNull: true
                },
                address2: {
                    label: 'Address 2',
                    type: 'string',
                    allowNull: true
                },
                city: {
                    label: 'City',
                    type: 'string',
                    allowNull: true
                },
                region: {
                    label: 'Region',
                    type: 'string',
                    allowNull: true
                },
                zip: {
                    label: 'ZIP',
                    type: 'string',
                    allowNull: true
                },
                latitude: {
                    label: 'Latitude',
                    type: 'string',
                    allowNull: true
                },
                longitude: {
                    label: 'Longitide',
                    type: 'string',
                    allowNull: true
                },
                country: {
                    label: 'Country',
                    type: 'string',
                    allowNull: true
                }
            },
            default: {
                city: { '@path': '$.traits.address.city' },
                region: { '@path': '$.traits.address.state' },
                zip: { '@path': '$.traits.address.postal_code' },
                address1: { '@path': '$.traits.address.street' },
                country: { '@path': '$.traits.address.country' }
            }
        },
        properties: {
            description: 'An object containing key/value pairs for any custom properties assigned to this profile.',
            label: 'Properties',
            type: 'object',
            default: {
                '@path': '$.properties'
            }
        },
        list_id: {
            label: 'List',
            description: `The Klaviyo list to add the profile to.`,
            type: 'string',
            dynamic: true
        },
        batch_size: { ...properties_1.batch_size, default: 10000, minimum: 100, maximum: 10000 },
        override_list_id: {
            unsafe_hidden: true,
            label: 'List ID Override',
            description: 'Klaviyo list ID to override the default list ID when provided in an event payload. Added to support backward compatibility with klaviyo(classic) and facilitate a seamless migration.',
            type: 'string',
            default: { '@path': '$.integrations.Klaviyo.listId' }
        },
        batch_keys: {
            label: 'Batch Keys',
            description: 'The keys to use for batching the events.',
            type: 'string',
            unsafe_hidden: true,
            required: false,
            multiple: true,
            default: ['list_id', 'override_list_id']
        }
    },
    hooks: {
        retlOnMappingSave: {
            label: 'Connect to a static list in Klaviyo',
            description: 'When saving this mapping, we will connect to a list in Klaviyo.',
            inputFields: {
                list_identifier: {
                    type: 'string',
                    label: 'Existing List ID',
                    description: 'The ID of the list in Klaviyo that users will be synced to. If defined, we will not create a new list.',
                    required: false,
                    dynamic: async (request) => {
                        return (0, functions_1.getListIdDynamicData)(request);
                    }
                },
                list_name: {
                    type: 'string',
                    label: 'Name of list to create',
                    description: 'The name of the list that you would like to create in Klaviyo.',
                    required: false
                }
            },
            outputTypes: {
                id: {
                    type: 'string',
                    label: 'ID',
                    description: 'The ID of the created Klaviyo list that users will be synced to.',
                    required: false
                },
                name: {
                    type: 'string',
                    label: 'List Name',
                    description: 'The name of the created Klaviyo list that users will be synced to.',
                    required: false
                }
            },
            performHook: async (request, { settings, hookInputs }) => {
                if (hookInputs.list_identifier) {
                    try {
                        return (0, functions_1.getList)(request, settings, hookInputs.list_identifier);
                    }
                    catch (e) {
                        const message = e.message || JSON.stringify(e) || 'Failed to get list';
                        const code = e.code || 'GET_LIST_FAILURE';
                        return {
                            error: {
                                message,
                                code
                            }
                        };
                    }
                }
                try {
                    return (0, functions_1.createList)(request, settings, hookInputs.list_name);
                }
                catch (e) {
                    const message = e.message || JSON.stringify(e) || 'Failed to create list';
                    const code = e.code || 'CREATE_LIST_FAILURE';
                    return {
                        error: {
                            message,
                            code
                        }
                    };
                }
            }
        }
    },
    dynamicFields: {
        list_id: async (request) => {
            return (0, functions_1.getListIdDynamicData)(request);
        }
    },
    perform: async (request, { payload, hookOutputs }) => {
        const { email, external_id, phone_number: initialPhoneNumber, enable_batching, batch_size, list_id: otherListId, override_list_id, country_code, batch_keys, ...otherAttributes } = payload;
        const list_id = hookOutputs?.retlOnMappingSave?.outputs?.id ?? override_list_id ?? otherListId;
        const phone_number = (0, functions_1.processPhoneNumber)(initialPhoneNumber, country_code);
        if (!email && !phone_number && !external_id) {
            throw new actions_core_1.PayloadValidationError('One of External ID, Phone Number and Email is required.');
        }
        const profileData = {
            data: {
                type: 'profile',
                attributes: {
                    email,
                    external_id,
                    phone_number,
                    ...otherAttributes
                }
            }
        };
        try {
            const profile = await request(`${config_1.API_URL}/profiles/`, {
                method: 'POST',
                json: profileData
            });
            if (list_id) {
                const content = JSON.parse(profile?.content);
                const id = content.data.id;
                await (0, functions_1.addProfileToList)(request, id, list_id);
            }
            return profile;
        }
        catch (error) {
            const { response } = error;
            if (response?.status === 409) {
                const content = JSON.parse(response?.content);
                const id = content?.errors[0]?.meta?.duplicate_profile_id;
                if (id) {
                    profileData.data.id = id;
                    const profile = await request(`${config_1.API_URL}/profiles/${id}`, {
                        method: 'PATCH',
                        json: profileData
                    });
                    if (list_id) {
                        await (0, functions_1.addProfileToList)(request, id, list_id);
                    }
                    return profile;
                }
            }
            throw error;
        }
    },
    performBatch: async (request, { payload, hookOutputs }) => {
        const multiStatusResponse = new actions_core_1.MultiStatusResponse();
        const filteredPayloads = [];
        const validPayloadIndicesBitmap = [];
        payload.forEach((payload, originalBatchIndex) => {
            const { payload: validPayload, error } = (0, functions_1.validateProfilePayload)(payload);
            if (error) {
                multiStatusResponse.setErrorResponseAtIndex(originalBatchIndex, error);
            }
            else {
                filteredPayloads.push(validPayload);
                validPayloadIndicesBitmap.push(originalBatchIndex);
            }
        });
        if (filteredPayloads.length === 0) {
            return multiStatusResponse;
        }
        payload.forEach((profile) => {
            if (hookOutputs?.retlOnMappingSave?.outputs?.id) {
                profile.list_id = hookOutputs.retlOnMappingSave.outputs.id;
            }
        });
        const listId = filteredPayloads[0]?.override_list_id || filteredPayloads[0]?.list_id;
        const importJobPayload = (0, functions_1.createImportJobPayload)(filteredPayloads, listId);
        try {
            const response = await (0, functions_1.sendImportJobRequest)(request, importJobPayload);
            (0, functions_1.updateMultiStatusWithSuccessData)(filteredPayloads, validPayloadIndicesBitmap, multiStatusResponse, response);
        }
        catch (error) {
            if (error instanceof actions_core_1.HTTPError) {
                await (0, functions_1.updateMultiStatusWithKlaviyoErrors)(filteredPayloads, error, multiStatusResponse, validPayloadIndicesBitmap);
            }
            else {
                throw error;
            }
        }
        return multiStatusResponse;
    }
};
exports.default = action;
//# sourceMappingURL=index.js.map