"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const properties_1 = require("../properties");
const errors_1 = require("../errors");
const utils_1 = require("../utils");
const api_1 = require("../api");
const versioning_info_1 = require("../versioning-info");
const defaultChoices = [
    { value: 'deals', label: 'Deals' },
    { value: 'tickets', label: 'Tickets' }
];
const defaultToObjectTypeChoices = [
    { value: 'contacts', label: 'Contacts' },
    { value: 'companies', label: 'Companies' }
];
const action = {
    title: 'Upsert Custom Object Record',
    description: 'Upsert records of Deals, Tickets or other Custom Objects in HubSpot.',
    fields: {
        createNewCustomRecord: {
            label: 'Create Custom Object Record if Not Found',
            description: 'If true, Segment will attempt to update an existing custom object record in HubSpot and if no record is found, Segment will create a new custom object record. If false, Segment will only attempt to update an existing record and never create a new record. This is set to true by default.',
            type: 'boolean',
            default: true
        },
        customObjectSearchFields: {
            label: 'Custom Object Search Fields',
            description: 'The unique field(s) used to search for an existing record in HubSpot to update. The fields provided here are then used to search. If a custom object is still not found, a new one is created.',
            type: 'object',
            defaultObjectUI: 'keyvalue:only'
        },
        objectType: {
            label: 'Object Type',
            description: 'The CRM object schema to use for creating a record. This can be a standard object (i.e. tickets, deals) or ***fullyQualifiedName*** of a custom object. Schema for the Custom Objects must be predefined in HubSpot. More information on Custom Objects and *fullyQualifiedName* in [HubSpot documentation](https://developers.hubspot.com/docs/api/crm/crm-custom-objects#retrieve-existing-custom-objects).',
            type: 'string',
            required: true,
            dynamic: true,
            allowNull: false,
            disabledInputMethods: ['literal', 'variable', 'function', 'freeform', 'enrichment']
        },
        properties: {
            label: 'Properties',
            description: 'Properties to send to HubSpot. On the left-hand side, input the internal name of the property as seen in your HubSpot account. On the right-hand side, map the Segment field that contains the value. Please make sure to include the object’s required properties. Any custom properties must be predefined in HubSpot. More information in [HubSpot documentation](https://knowledge.hubspot.com/crm-setup/manage-your-properties#create-custom-properties).',
            type: 'object',
            required: true,
            defaultObjectUI: 'keyvalue:only',
            allowNull: false
        },
        searchFieldsToAssociateCustomObjects: {
            label: 'Search Fields to Associate custom Object',
            description: 'The unique field(s) used to search for an existing custom record in HubSpot to get toObjectId so that segment will associate the record with this record. If a Record is not found on the basis of data provided here in key:value format will skip the association.',
            type: 'object',
            defaultObjectUI: 'keyvalue:only'
        },
        toObjectType: {
            label: 'ObjectType to associate',
            description: 'The CRM object schema to use for associating a record. This can be a standard object (i.e. tickets, deals, contacts, companies) or ***fullyQualifiedName*** of a custom object. Schema for the Custom Objects must be predefined in HubSpot. More information on Custom Objects and *fullyQualifiedName* in [HubSpot documentation](https://developers.hubspot.com/docs/api/crm/crm-custom-objects#retrieve-existing-custom-objects).',
            type: 'string',
            dynamic: true,
            disabledInputMethods: ['literal', 'variable', 'function', 'freeform', 'enrichment']
        },
        associationLabel: {
            label: 'Association Label',
            description: 'Type of Association between two objectType',
            type: 'string',
            dynamic: true
        }
    },
    dynamicFields: {
        objectType: async (request, { payload }) => {
            return getCustomObjects(request, defaultChoices, payload.toObjectType);
        },
        toObjectType: async (request, { payload }) => {
            return getCustomObjects(request, [...defaultChoices, ...defaultToObjectTypeChoices], payload.objectType);
        },
        associationLabel: async (request, { payload }) => {
            return getAssociationLabel(request, payload);
        }
    },
    perform: async (request, { payload }) => {
        let searchCustomResponse = null;
        let searchCustomResponseToAssociate = null;
        const hubspotApiClient = new api_1.Hubspot(request, payload.objectType, payload.toObjectType);
        let association = null;
        try {
            searchCustomResponse = await hubspotApiClient.search({ ...payload.customObjectSearchFields }, payload.objectType, [], []);
        }
        catch (e) {
            if (e?.response?.status === 400) {
                throw errors_1.CustomSearchThrowableError;
            }
            throw e;
        }
        const parsedAssociationType = payload.associationLabel
            ? parseAssociationType(payload.associationLabel)
            : null;
        searchCustomResponseToAssociate = await hubspotApiClient.getObjectResponseToAssociate(payload.searchFieldsToAssociateCustomObjects, parsedAssociationType);
        const toCustomObjectId = searchCustomResponseToAssociate?.data?.total === 1 ? searchCustomResponseToAssociate?.data.results[0].id : null;
        association = createAssociationObject(toCustomObjectId, parsedAssociationType);
        let upsertCustomRecordResponse;
        const properties = { ...(0, utils_1.flattenObject)(payload.properties) };
        if (!searchCustomResponse?.data || searchCustomResponse?.data?.total === 0) {
            const createNewCustomRecord = payload?.createNewCustomRecord ?? true;
            if (!createNewCustomRecord) {
                return 'There was no record found to update. If you want to create a new custom object record in such cases, enable the Create Custom Object Record if Not Found flag';
            }
            upsertCustomRecordResponse = await hubspotApiClient.create(properties, association ? [association] : []);
        }
        else {
            if (searchCustomResponse?.data?.total > 1) {
                throw errors_1.MultipleCustomRecordsInSearchResultThrowableError;
            }
            upsertCustomRecordResponse = await hubspotApiClient.update(searchCustomResponse.data.results[0].id, properties);
            if (toCustomObjectId && parsedAssociationType) {
                await hubspotApiClient.associate(searchCustomResponse.data.results[0].id, toCustomObjectId, [
                    {
                        associationCategory: parsedAssociationType.associationCategory,
                        associationTypeId: parsedAssociationType.associationTypeId
                    }
                ]);
            }
        }
        if (searchCustomResponseToAssociate?.data && searchCustomResponseToAssociate?.data?.total > 1) {
            throw errors_1.MultipleCustomRecordsInSearchResultToAssociateThrowableError;
        }
        return upsertCustomRecordResponse;
    }
};
async function getCustomObjects(request, defaultChoices, objectType) {
    try {
        const response = await request(`${properties_1.HUBSPOT_BASE_URL}/crm/${versioning_info_1.HUBSPOT_CRM_API_VERSION}/schemas?archived=false`, {
            method: 'GET',
            skipResponseCloning: true
        });
        const choices = response.data.results
            .filter((res) => res.fullyQualifiedName != objectType)
            .map((schema) => ({
            label: schema.labels.plural,
            value: schema.fullyQualifiedName
        }));
        return {
            choices: [...choices, ...defaultChoices]
        };
    }
    catch (err) {
        return {
            choices: [],
            error: {
                message: err?.response?.data?.message ?? 'Unknown error',
                code: err?.response?.status + '' ?? '500'
            }
        };
    }
}
async function getAssociationLabel(request, payload) {
    try {
        const response = await request(`${properties_1.HUBSPOT_BASE_URL}/crm/${versioning_info_1.HUBSPOT_CRM_ASSOCIATIONS_API_VERSION}/associations/${payload.objectType}/${payload.toObjectType}/labels`, {
            method: 'GET',
            skipResponseCloning: true
        });
        const choices = response?.data?.results?.map((res) => ({
            label: !res.label ? `Unlabeled Association (Type ${res.typeId})` : res.label,
            value: `${res.category}:${res.typeId}`
        }));
        return {
            choices
        };
    }
    catch (err) {
        return {
            choices: [],
            error: {
                message: err?.response?.data?.message ?? 'Unknown error',
                code: err?.response?.status + '' ?? '500'
            }
        };
    }
}
function createAssociationObject(toCustomObjectId, associationType) {
    return toCustomObjectId && associationType
        ? {
            to: {
                id: toCustomObjectId
            },
            types: [
                {
                    associationCategory: associationType.associationCategory,
                    associationTypeId: associationType.associationTypeId
                }
            ]
        }
        : null;
}
function parseAssociationType(associationLabel) {
    const associationType = associationLabel.split(':');
    return {
        associationCategory: associationType[0],
        associationTypeId: Number(associationType[1])
    };
}
exports.default = action;
//# sourceMappingURL=index.js.map