"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getCategories = exports.getDataExtensionFields = exports.getDataExtensions = exports.selectOrCreateDataExtension = void 0;
exports.upsertRows = upsertRows;
exports.upsertRowsV2 = upsertRowsV2;
exports.executeUpsertWithMultiStatus = executeUpsertWithMultiStatus;
const actions_core_1 = require("@segment/actions-core");
const xml_js_1 = require("xml-js");
function generateRows(payloads) {
    const rows = [];
    payloads.forEach((payload) => {
        rows.push({
            keys: payload.keys,
            values: payload.values
        });
    });
    return rows;
}
function isRetryableError(errData, status) {
    return (status === 400 &&
        errData?.errorcode === 10006 &&
        errData?.message.includes('Unable to save rows for data extension ID') &&
        !errData?.additionalErrors);
}
function upsertRows(request, subdomain, payloads) {
    const { key, id } = payloads[0];
    if (!key && !id) {
        throw new actions_core_1.IntegrationError(`In order to send an event to a data extension either Data Extension ID or Data Extension Key must be defined.`, 'Misconfigured required field', 400);
    }
    const rows = generateRows(payloads);
    if (key) {
        return request(`https://${subdomain}.rest.marketingcloudapis.com/hub/v1/dataevents/key:${key}/rowset`, {
            method: 'POST',
            json: rows
        });
    }
    else {
        return request(`https://${subdomain}.rest.marketingcloudapis.com/hub/v1/dataevents/${id}/rowset`, {
            method: 'POST',
            json: rows
        });
    }
}
function upsertRowsV2(request, subdomain, payloads, dataExtensionId) {
    if (!dataExtensionId) {
        throw new actions_core_1.IntegrationError(`In order to send an event to a data extension Data Extension ID must be defined.`, 'Misconfigured required field', 400);
    }
    const rows = generateRows(payloads);
    return request(`https://${subdomain}.rest.marketingcloudapis.com/hub/v1/dataevents/${dataExtensionId}/rowset`, {
        method: 'POST',
        json: rows
    });
}
async function executeUpsertWithMultiStatus(request, subdomain, payloads, dataExtensionId, statsContext) {
    const multiStatusResponse = new actions_core_1.MultiStatusResponse();
    let response;
    const rows = generateRows(payloads);
    try {
        if (dataExtensionId) {
            response = await upsertRowsV2(request, subdomain, payloads, dataExtensionId);
        }
        else {
            response = await upsertRows(request, subdomain, payloads);
        }
        if (response) {
            const responseData = response.data;
            payloads.forEach((_, index) => {
                multiStatusResponse.setSuccessResponseAtIndex(index, {
                    status: 200,
                    sent: rows[index],
                    body: responseData[index] ? responseData[index] : {}
                });
            });
        }
    }
    catch (error) {
        if (error instanceof actions_core_1.IntegrationError && error.code === 'Misconfigured required field') {
            payloads.forEach((_, index) => {
                multiStatusResponse.setErrorResponseAtIndex(index, {
                    status: 400,
                    errortype: 'PAYLOAD_VALIDATION_FAILED',
                    errormessage: `In order to send an event to a data extension either Data Extension ID or Data Extension Key must be defined.`
                });
            });
            return multiStatusResponse;
        }
        if (!error.response?.data) {
            if (statsContext) {
                const { tags, statsClient } = statsContext;
                statsClient?.incr('sfmc_upsert_rows_error', 1, [...tags]);
            }
            payloads.forEach((_, index) => {
                multiStatusResponse.setErrorResponseAtIndex(index, {
                    status: 500,
                    errormessage: error.message
                });
            });
            return multiStatusResponse;
        }
        const err = error;
        if (err?.response?.status === 401) {
            throw error;
        }
        const errData = err?.response?.data;
        const additionalError = err?.response?.data?.additionalErrors &&
            err.response.data.additionalErrors.length > 0 &&
            err.response.data.additionalErrors;
        let status = 500;
        const isRetryable = isRetryableError(errData, err?.response?.status);
        statsContext?.statsClient?.incr('sfmc_upsert_rows_error', 1, [...statsContext.tags, `retryable:${isRetryable}`]);
        if (!isRetryable && err?.response?.status) {
            status = err.response.status;
        }
        payloads.forEach((_, index) => {
            multiStatusResponse.setErrorResponseAtIndex(index, {
                status: status,
                errormessage: additionalError ? additionalError[0].message : errData?.message || '',
                sent: rows[index],
                body: additionalError ? additionalError : errData
            });
        });
    }
    return multiStatusResponse;
}
const getAccessToken = async (request, settings) => {
    const baseUrl = `https://${settings.subdomain}.auth.marketingcloudapis.com/v2/token`;
    const res = await request(`${baseUrl}`, {
        method: 'POST',
        body: new URLSearchParams({
            account_id: settings.account_id,
            client_id: settings.client_id,
            client_secret: settings.client_secret,
            grant_type: 'client_credentials'
        })
    });
    return { accessToken: res.data.access_token, soapInstanceUrl: res.data.soap_instance_url };
};
const dataExtensionRequest = async (request, hookInputs, auth) => {
    if (!hookInputs) {
        return { id: '', key: '', error: 'No inputs provided' };
    }
    if (!hookInputs.columns) {
        return { id: '', key: '', error: 'No columns provided' };
    }
    const fields = hookInputs.columns.map((column, i) => {
        return {
            name: column.name,
            type: column.type,
            isNullable: column.isNullable,
            isPrimaryKey: column.isPrimaryKey,
            length: column.length,
            scale: column.scale,
            description: column.description || '',
            ordinal: i,
            isTemplateField: false,
            isHidden: false,
            isReadOnly: false,
            isInheritable: false,
            isOverridable: false,
            mustOverride: false
        };
    });
    try {
        const response = await request(`https://${auth.subdomain}.rest.marketingcloudapis.com/data/v1/customobjects`, {
            method: 'POST',
            json: {
                name: hookInputs.name,
                description: hookInputs.description,
                categoryId: hookInputs.categoryId,
                isSendable: hookInputs.isSendable,
                sendableCustomObjectField: hookInputs.sendableCustomObjectField,
                sendableSubscriberField: hookInputs.sendableSubscriberField,
                fields
            },
            headers: {
                authorization: `Bearer ${auth.accessToken}`
            }
        });
        if (response.status !== 201) {
            return { id: '', key: '', error: `Failed to create Data Extension` };
        }
        return {
            id: response.data.id,
            key: response.data.key
        };
    }
    catch (error) {
        return { id: '', key: '', error: error.response.data.message };
    }
};
async function createDataExtension(request, subdomain, hookInputs, settings) {
    if (!hookInputs) {
        return {
            error: { message: 'No inputs provided', code: 'ERROR' }
        };
    }
    const { accessToken } = await getAccessToken(request, settings);
    const { id, key, error } = await dataExtensionRequest(request, hookInputs, { subdomain, accessToken });
    if (error || !id || !key) {
        return {
            error: { message: error || 'Unknown Error', code: 'ERROR' }
        };
    }
    return {
        successMessage: `Data Extension ${hookInputs.name} created successfully with External Key ${key}`,
        savedData: {
            id,
            name: hookInputs.name
        }
    };
}
const selectDataExtensionRequest = async (request, hookInputs, auth) => {
    if (!hookInputs) {
        return { id: '', name: '', error: 'No inputs provided' };
    }
    if (!hookInputs.dataExtensionId) {
        return { id: '', name: '', error: 'No Data Extension Id provided' };
    }
    try {
        const response = await request(`https://${auth.subdomain}.rest.marketingcloudapis.com/data/v1/customobjects/${hookInputs.dataExtensionId}`, {
            method: 'GET',
            headers: {
                authorization: `Bearer ${auth.accessToken}`
            }
        });
        if (response.status !== 200) {
            return { id: '', name: '', error: `Failed to select Data Extension` };
        }
        return {
            id: response.data.id,
            name: response.data.name
        };
    }
    catch (err) {
        const errorCode = typeof err.response.data.errorcode === 'number'
            ? err.response.data.errorcode.toString()
            : err.response.data.errorcode;
        const errorMessage = err.response.data.message;
        if (errorCode === '20002') {
            return {
                id: hookInputs.dataExtensionId,
                name: 'Unknown (Insufficient Authentication Error)',
                error: `${errorMessage} To resolve this authentication issue refer to the required permissions under 'Getting Started' in the documentation at https://segment.com/docs/connections/destinations/catalog/actions-salesforce-marketing-cloud/`
            };
        }
        return { id: '', name: '', error: err.response.data.message };
    }
};
async function selectDataExtension(request, subdomain, hookInputs, settings) {
    if (!hookInputs) {
        return {
            error: { message: 'No inputs provided', code: 'ERROR' }
        };
    }
    const { accessToken } = await getAccessToken(request, settings);
    const { id, name, error } = await selectDataExtensionRequest(request, hookInputs, { subdomain, accessToken });
    if (error && id) {
        return {
            error: { message: error, code: 'Authentication Error' },
            savedData: { id, name: name }
        };
    }
    if (error || !id) {
        return {
            error: { message: error || 'Unknown Error', code: 'ERROR' }
        };
    }
    return {
        successMessage: `Data Extension ${name} selected successfully with External ID ${id}`,
        savedData: {
            id,
            name: name
        }
    };
}
const selectOrCreateDataExtension = async (request, subdomain, hookInputs, settings) => {
    if (hookInputs.operation === 'create') {
        return await createDataExtension(request, subdomain, hookInputs, settings);
    }
    else if (hookInputs.operation === 'select') {
        return await selectDataExtension(request, subdomain, hookInputs, settings);
    }
    return {
        error: { message: 'Invalid operation', code: 'ERROR' }
    };
};
exports.selectOrCreateDataExtension = selectOrCreateDataExtension;
const getDataExtensionsRequest = async (request, searchQuery, auth) => {
    try {
        const response = await request(`https://${auth.subdomain}.rest.marketingcloudapis.com/data/v1/customobjects`, {
            method: 'get',
            searchParams: {
                $search: searchQuery
            },
            headers: {
                authorization: `Bearer ${auth.accessToken}`
            }
        });
        if (response.status !== 200) {
            return { error: { message: 'Failed to fetch Data Extensions', code: 'BAD_REQUEST' } };
        }
        const choices = response.data.items;
        return {
            results: choices.map((choice) => {
                return {
                    value: choice.id,
                    label: choice.name
                };
            })
        };
    }
    catch (err) {
        const errorCode = typeof err.response.data.errorcode === 'number'
            ? err.response.data.errorcode.toString()
            : err.response.data.errorcode;
        const errorMessage = err.response.data.message;
        if (errorCode === '20002') {
            return {
                error: {
                    message: `${errorMessage}. Please input a data extension ID manually to configure your mapping. To resolve this authentication issue refer to the required permissions under 'Getting Started' in the documentation at https://segment.com/docs/connections/destinations/catalog/actions-salesforce-marketing-cloud/`,
                    code: errorCode
                }
            };
        }
        return { error: { message: err.response.data.message, code: errorCode || 'BAD_REQUEST' } };
    }
};
const getDataExtensions = async (request, subdomain, settings, query) => {
    let searchQuery = '_';
    if (query && query !== '') {
        searchQuery = query;
    }
    const { accessToken } = await getAccessToken(request, settings);
    const { results, error } = await getDataExtensionsRequest(request, searchQuery, { subdomain, accessToken });
    if (error) {
        return {
            choices: [],
            error: error
        };
    }
    if (!results || (Array.isArray(results) && results.length === 0)) {
        return {
            choices: [],
            error: { message: 'No Data Extensions found', code: 'NOT_FOUND' }
        };
    }
    return {
        choices: results
    };
};
exports.getDataExtensions = getDataExtensions;
const getDataExtensionFieldsRequest = async (request, dataExtensionId, auth, primaryKey) => {
    try {
        const response = await request(`https://${auth.subdomain}.rest.marketingcloudapis.com/data/v1/customobjects/${dataExtensionId}/fields`, {
            method: 'GET',
            headers: {
                authorization: `Bearer ${auth.accessToken}`
            }
        });
        if (response.status !== 200) {
            return { error: { message: 'Failed to fetch Data Extension fields', code: 'BAD_REQUEST' } };
        }
        const filteredItems = response.data.fields.filter((field) => field.isPrimaryKey === primaryKey);
        const choices = filteredItems.map((field) => {
            return { value: field.name, label: field.name };
        });
        return { results: choices };
    }
    catch (err) {
        return { error: { message: err.response.data.message, code: 'BAD_REQUEST' } };
    }
};
const getDataExtensionFields = async (request, subdomain, settings, dataExtensionID, primaryKey) => {
    if (!dataExtensionID) {
        return { choices: [], error: { message: 'No Data Extension ID provided', code: 'BAD_REQUEST' } };
    }
    const { accessToken } = await getAccessToken(request, settings);
    const { results, error } = await getDataExtensionFieldsRequest(request, dataExtensionID, { subdomain, accessToken }, primaryKey);
    if (error) {
        return {
            choices: [],
            error: error
        };
    }
    if (!results || (Array.isArray(results) && results.length === 0)) {
        return {
            choices: [],
            error: { message: 'No Data Extension fields found', code: 'NOT_FOUND' }
        };
    }
    return {
        choices: results
    };
};
exports.getDataExtensionFields = getDataExtensionFields;
const getCategoriesRequest = async (request, auth) => {
    try {
        const response = await request(`${auth.soapInstanceUrl}/Service.asmx`, {
            method: 'POST',
            headers: {
                'Content-Type': 'text/xml',
                SOAPAction: 'Retrieve'
            },
            body: `<?xml version="1.0" encoding="UTF-8"?>
        <SOAP-ENV:Envelope
          xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
          xmlns:xsd="http://www.w3.org/2001/XMLSchema"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
          <SOAP-ENV:Header>
            <fueloauth xmlns="http://exacttarget.com">${auth.accessToken}</fueloauth>
          </SOAP-ENV:Header>
          <SOAP-ENV:Body>
            <RetrieveRequestMsg
              xmlns="http://exacttarget.com/wsdl/partnerAPI">
                <RetrieveRequest>
                  <ObjectType>DataFolder</ObjectType>
                  <Properties>ID</Properties>
                  <Properties>Name</Properties>
                  <Properties>ContentType</Properties>
                  <Filter xsi:type="SimpleFilterPart">
                  <Property>ContentType</Property>
                  <SimpleOperator>equals</SimpleOperator>
                  <Value>dataextension</Value>
                  </Filter>
                </RetrieveRequest>
            </RetrieveRequestMsg>
          </SOAP-ENV:Body>
        </SOAP-ENV:Envelope>
        `
        });
        const convert = (0, xml_js_1.xml2js)(response.content, { compact: true });
        const items = convert['soap:Envelope']['soap:Body']['RetrieveResponseMsg']['Results'].map((item) => {
            const type = item.ContentType._text;
            return {
                label: item.Name._text,
                value: item.ID._text,
                description: `ContentType: ${type}`
            };
        });
        return {
            results: items
        };
    }
    catch (err) {
        return { error: { message: err.response.data.message, code: 'BAD_REQUEST' } };
    }
};
const getCategories = async (request, settings) => {
    const { accessToken, soapInstanceUrl } = await getAccessToken(request, settings);
    const { results, error } = await getCategoriesRequest(request, { soapInstanceUrl, accessToken });
    if (error) {
        return {
            choices: [],
            error: error
        };
    }
    return {
        choices: results || []
    };
};
exports.getCategories = getCategories;
//# sourceMappingURL=sfmc-operations.js.map