"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 action = {
    title: 'Upsert Company',
    description: 'Create or update a company in HubSpot.',
    defaultSubscription: 'type = "group"',
    fields: {
        groupid: {
            label: 'Unique Company Identifier',
            description: 'A unique identifier you assign to a company. Segment creates a custom property in HubSpot to store this value for each company so it can be used as a unique search field. Segment recommends not changing this value once set to avoid creating duplicate companies.',
            type: 'string',
            required: true,
            default: {
                '@if': {
                    exists: { '@path': '$.groupId' },
                    then: { '@path': '$.groupId' },
                    else: { '@path': '$.context.groupId' }
                }
            }
        },
        createNewCompany: {
            label: 'Create Company if Not Found',
            description: 'If true, Segment will attempt to update an existing company in HubSpot and if no company is found, Segment will create a new company. If false, Segment will only attempt to update an existing company and never create a new company. This is set to true by default.',
            type: 'boolean',
            required: true,
            default: true
        },
        associateContact: {
            label: 'Associate Contact with Company',
            description: 'If true, Segment will associate the company with the user identified in your payload. If no contact is found in HubSpot, an error is thrown and the company is not created/updated. If false, Segment will not attempt to associate a contact with the company and companies can be created/updated without requiring a contact association. This is set to true by default.',
            type: 'boolean',
            required: true,
            default: true
        },
        companysearchfields: {
            label: 'Company Search Fields',
            description: 'The unique field(s) used to search for an existing company in HubSpot to update. By default, Segment creates a custom property to store groupId for each company and uses this property to search for companies. If a company is not found, the fields provided here are then used to search. If a company is still not found, a new one is created.',
            type: 'object',
            defaultObjectUI: 'keyvalue:only'
        },
        name: {
            label: 'Company Name',
            description: 'The name of the company.',
            type: 'string',
            default: {
                '@path': '$.traits.name'
            }
        },
        description: {
            label: 'Company Description',
            description: 'A short statement about the company’s mission and goals.',
            type: 'string',
            default: {
                '@path': '$.traits.description'
            }
        },
        address: {
            label: 'Street Address',
            description: 'The street address of the company.',
            type: 'string',
            default: {
                '@path': '$.traits.address.street'
            }
        },
        city: {
            label: 'City',
            description: 'The city where the company is located.',
            type: 'string',
            default: {
                '@path': '$.traits.address.city'
            }
        },
        state: {
            label: 'State',
            description: 'The state or region where the company is located.',
            type: 'string',
            default: {
                '@path': '$.traits.address.state'
            }
        },
        zip: {
            label: 'Postal Code',
            description: 'The postal or zip code of the company.',
            type: 'string',
            default: {
                '@if': {
                    exists: { '@path': '$.traits.address.postalCode' },
                    then: { '@path': '$.traits.address.postalCode' },
                    else: { '@path': '$.traits.address.postal_code' }
                }
            }
        },
        domain: {
            label: 'Domain',
            description: 'The company’s website domain.',
            type: 'string',
            default: {
                '@path': '$.traits.website'
            }
        },
        phone: {
            label: 'Phone',
            description: 'The company’s primary phone number.',
            type: 'string',
            default: {
                '@path': '$.traits.phone'
            }
        },
        numberofemployees: {
            label: 'Number of Employees',
            description: 'The total number of people who work for the company.',
            type: 'integer',
            default: {
                '@path': '$.traits.employees'
            }
        },
        industry: {
            label: 'Industry',
            description: 'The type of business the company performs.',
            type: 'string',
            default: {
                '@path': '$.traits.industry'
            }
        },
        lifecyclestage: {
            label: 'Lifecycle Stage',
            description: 'The company’s stage within the marketing/sales process. See more information on default and custom stages in [HubSpot’s documentation](https://knowledge.hubspot.com/contacts/use-lifecycle-stages). Segment supports moving status forwards or backwards.',
            type: 'string'
        },
        properties: {
            label: 'Other Properties',
            description: `Any other default or custom company properties. 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. Custom properties must be predefined in HubSpot. See more information in [HubSpot’s documentation](https://knowledge.hubspot.com/crm-setup/manage-your-properties#create-custom-properties). Important: Do not use ’${properties_1.SEGMENT_UNIQUE_IDENTIFIER}’ here as it is an internal property and will result in an an error.`,
            type: 'object',
            defaultObjectUI: 'keyvalue:only',
            allowNull: false
        }
    },
    perform: async (request, { payload, transactionContext }) => {
        if (payload.properties?.[properties_1.SEGMENT_UNIQUE_IDENTIFIER]) {
            throw errors_1.RestrictedPropertyThrowableError;
        }
        if (payload.associateContact && !transactionContext?.transaction?.contact_id) {
            throw errors_1.MissingIdentityCallThrowableError;
        }
        const hubspotApiClient = new api_1.Hubspot(request, 'companies');
        const companyProperties = {
            name: payload.name?.trim(),
            description: payload.description?.trim(),
            address: payload.address?.trim(),
            city: payload.city?.trim(),
            state: payload.state?.trim(),
            zip: payload.zip?.trim(),
            domain: payload.domain?.trim(),
            phone: payload.phone?.trim(),
            numberofemployees: payload.numberofemployees,
            industry: payload.industry?.trim(),
            lifecyclestage: payload.lifecyclestage?.toLocaleLowerCase().trim(),
            [properties_1.SEGMENT_UNIQUE_IDENTIFIER]: payload.groupid,
            ...(0, utils_1.flattenObject)(payload.properties)
        };
        let companyId = '';
        try {
            const updateCompanyResponse = await hubspotApiClient.update(payload.groupid, companyProperties, properties_1.SEGMENT_UNIQUE_IDENTIFIER);
            companyId = updateCompanyResponse.data.id;
        }
        catch (e) {
            const error = e;
            if ((0, errors_1.isSegmentUniqueIdentifierPropertyError)(error, properties_1.SEGMENT_UNIQUE_IDENTIFIER)) {
                await createSegmentUniqueIdentifierProperty(request);
                throw errors_1.SegmentUniqueIdentifierMissingRetryableError;
            }
            if (error?.response?.status !== 404 &&
                !(0, errors_1.isSegmentUniqueIdentifierPropertyError)(error, properties_1.SEGMENT_UNIQUE_IDENTIFIER)) {
                throw e;
            }
        }
        if (!companyId) {
            let searchCompanyResponse = null;
            if (typeof payload.companysearchfields === 'object' && Object.keys(payload.companysearchfields).length > 0) {
                try {
                    const responseProperties = ['name', 'domain', 'lifecyclestage', properties_1.SEGMENT_UNIQUE_IDENTIFIER];
                    const responseSortBy = ['name'];
                    searchCompanyResponse = await hubspotApiClient.search({ ...payload.companysearchfields }, 'companies', responseProperties, responseSortBy);
                }
                catch (e) {
                    if (e?.response?.status === 400) {
                        throw errors_1.CompanySearchThrowableError;
                    }
                    throw e;
                }
            }
            if (!searchCompanyResponse?.data || searchCompanyResponse?.data?.total === 0) {
                if (!payload.createNewCompany) {
                    return;
                }
                const createCompanyWrapper = async function () {
                    return await hubspotApiClient.create(companyProperties);
                };
                companyId = await upsertCompanyWithRetry(request, createCompanyWrapper);
            }
            else {
                if (searchCompanyResponse.data.total > 1) {
                    throw errors_1.MultipleCompaniesInSearchResultThrowableError;
                }
                companyId = searchCompanyResponse.data.results[0].id;
                const updateCompanyWrapper = async function () {
                    return await hubspotApiClient.update(companyId, companyProperties);
                };
                await upsertCompanyWithRetry(request, updateCompanyWrapper);
            }
        }
        if (payload.associateContact && transactionContext?.transaction?.contact_id) {
            await associateCompanyToContact(request, companyId, transactionContext.transaction.contact_id, properties_1.ASSOCIATION_TYPE);
        }
    }
};
function createSegmentUniqueIdentifierProperty(request) {
    const segmentUniqueIdentifierProperty = {
        name: properties_1.SEGMENT_UNIQUE_IDENTIFIER,
        label: 'Segment Group ID',
        description: 'Unique Property to map Segment Group ID with a HubSpot Company Object',
        groupName: 'companyinformation',
        type: 'string',
        fieldType: 'text',
        hidden: true,
        displayOrder: -1,
        hasUniqueValue: true,
        formField: false
    };
    return request(`${properties_1.HUBSPOT_BASE_URL}/crm/${versioning_info_1.HUBSPOT_CRM_API_VERSION}/properties/companies`, {
        method: 'POST',
        json: {
            ...segmentUniqueIdentifierProperty
        }
    });
}
function associateCompanyToContact(request, companyId, contactId, associationType) {
    return request(`${properties_1.HUBSPOT_BASE_URL}/crm/${versioning_info_1.HUBSPOT_CRM_API_VERSION}/objects/companies/${companyId}/associations/contacts/${contactId}/${associationType}`, {
        method: 'PUT'
    });
}
async function upsertCompanyWithRetry(request, upsertCompanyFunction) {
    try {
        const upsertCompanyResponse = await upsertCompanyFunction();
        return upsertCompanyResponse.data.id;
    }
    catch (e) {
        const error = e;
        if ((0, errors_1.isSegmentUniqueIdentifierPropertyError)(error, properties_1.SEGMENT_UNIQUE_IDENTIFIER)) {
            try {
                await createSegmentUniqueIdentifierProperty(request);
            }
            catch (e) {
                if (e?.response?.status !== 409) {
                    throw e;
                }
            }
            const upsertCompanyResponse = await upsertCompanyFunction();
            return upsertCompanyResponse.data.id;
        }
        else {
            throw e;
        }
    }
}
exports.default = action;
//# sourceMappingURL=index.js.map