"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createContactList = exports.getContactListId = exports.getContactListIdByName = exports.patchContactList = exports.criteoAuthenticate = exports.getAccessToken = exports.hash = void 0;
const crypto_1 = require("crypto");
const actions_core_1 = require("@segment/actions-core");
const versioning_info_1 = require("./versioning-info");
const BASE_API_URL = `https://api.criteo.com/${versioning_info_1.CRITEO_AUDIENCES_API_VERSION}`;
const hash = (value) => {
    if (value === undefined)
        return;
    const hash = (0, crypto_1.createHash)('sha256');
    hash.update(value);
    return hash.digest('hex');
};
exports.hash = hash;
class CriteoAPIError extends actions_core_1.IntegrationError {
    constructor(message, code, status, error) {
        super(message, code, status);
        this.error = error;
    }
}
const getRequestHeaders = async (request, credentials) => {
    credentials = await (0, exports.criteoAuthenticate)(request, credentials);
    return {
        Accept: 'application/json',
        'Content-Type': 'application/json',
        Authorization: `Bearer ` + credentials.access_token
    };
};
const getAccessToken = async (request, credentials) => {
    const res = await request(`https://api.criteo.com/oauth2/token`, {
        method: 'POST',
        body: new URLSearchParams({
            client_id: credentials.client_id,
            client_secret: credentials.client_secret,
            grant_type: 'client_credentials'
        }),
        headers: {
            Accept: 'text/plain',
            'Content-Type': 'application/x-www-form-urlencoded'
        }
    });
    const body = await res.json();
    if (res.status !== 200)
        throw new actions_core_1.RetryableError(`Error while getting an access token`);
    return body.access_token;
};
exports.getAccessToken = getAccessToken;
const criteoAuthenticate = async (request, credentials) => {
    if (!credentials.access_token)
        credentials.access_token = await (0, exports.getAccessToken)(request, credentials);
    return credentials;
};
exports.criteoAuthenticate = criteoAuthenticate;
const patchContactList = async (request, operation, credentials) => {
    if (isNaN(+operation.contactlist_id))
        throw new actions_core_1.IntegrationError(`The Audience Segment ID should be a number (${operation.contactlist_id})`, 'Invalid input', 400);
    const endpoint = `${BASE_API_URL}/marketing-solutions/audience-segments/${operation.contactlist_id}/contact-list`;
    const headers = await getRequestHeaders(request, credentials);
    const payload = {
        data: {
            type: 'ContactlistAmendment',
            attributes: {
                operation: operation.operation_type,
                identifierType: 'email',
                identifiers: operation.user_list
            }
        }
    };
    return request(endpoint, {
        method: 'PATCH',
        json: payload,
        headers: headers
    });
};
exports.patchContactList = patchContactList;
const getContactListIdByName = async (request, advertiser_id, audience_segment_name, credentials) => {
    if (isNaN(+advertiser_id))
        throw new actions_core_1.IntegrationError('The Advertiser ID should be a number', 'Invalid input', 400);
    const LIMIT = 100;
    const headers = await getRequestHeaders(request, credentials);
    const payload = {
        data: {
            attributes: {
                audienceSegmentTypes: ['ContactList'],
                advertiserIds: [advertiser_id]
            }
        }
    };
    let continue_search = true;
    let offset = 0;
    let body;
    do {
        const endpoint = `${BASE_API_URL}/marketing-solutions/audience-segments/search?limit=${LIMIT}&offset=${offset}`;
        const response = await request(endpoint, {
            method: 'POST',
            skipResponseCloning: true,
            headers: headers,
            json: payload
        });
        body = response.data;
        if (response.status !== 200)
            throw new actions_core_1.RetryableError("Error while fetching the Advertiser's audiences");
        for (const contactlist of body.data) {
            if (contactlist.attributes.name === audience_segment_name)
                return contactlist.id;
        }
        offset += LIMIT;
        continue_search = body.meta.totalItems > offset;
    } while (continue_search);
};
exports.getContactListIdByName = getContactListIdByName;
const getContactListId = async (request, advertiser_id, name, credentials) => {
    let contactlist_id = undefined;
    if (!name)
        throw new actions_core_1.IntegrationError(`Invalid Audience Segment Name: ${name}`, 'Invalid input', 400);
    contactlist_id = await (0, exports.getContactListIdByName)(request, advertiser_id, name, credentials);
    if (contactlist_id && !isNaN(+contactlist_id))
        return contactlist_id;
    try {
        return await (0, exports.createContactList)(request, advertiser_id, name, credentials);
    }
    catch (e) {
        if (e instanceof CriteoAPIError) {
            if (e.error && e.error.code === 'name-must-be-unique') {
                contactlist_id = await (0, exports.getContactListIdByName)(request, advertiser_id, name, credentials);
                if (contactlist_id && !isNaN(+contactlist_id))
                    return contactlist_id;
            }
        }
        throw e;
    }
};
exports.getContactListId = getContactListId;
const createContactList = async (request, advertiser_id, name, credentials) => {
    if (!name)
        throw new actions_core_1.IntegrationError(`Invalid Contact List Name: ${name}`, 'Invalid audience', 400);
    if (isNaN(+advertiser_id))
        throw new actions_core_1.IntegrationError('The Advertiser ID should be a number', 'Invalid input', 400);
    const endpoint = `${BASE_API_URL}/marketing-solutions/audience-segments/create`;
    const headers = await getRequestHeaders(request, credentials);
    const payload = {
        data: [
            {
                attributes: {
                    advertiserId: advertiser_id,
                    name: name,
                    description: name,
                    contactList: {}
                }
            }
        ]
    };
    const response = await request(endpoint, { method: 'POST', headers: headers, json: payload, throwHttpErrors: false });
    const body = await response.json();
    if (response.status !== 200) {
        const err = body.errors && body.errors[0] ? body.errors[0] : undefined;
        throw new CriteoAPIError(`Error while creating the Contact List`, 'Criteo contact list creation error', 400, err);
    }
    if (!Array.isArray(body.data)) {
        throw new CriteoAPIError(`Error while creating the Contact List. data[] not returned`, 'Criteo contact list creation error', 403);
    }
    if (body.data.length === 0) {
        throw new CriteoAPIError(`Error while creating the Contact List. data[] is empty`, 'Criteo contact list creation error', 403);
    }
    if (body.data[0].id === undefined) {
        throw new CriteoAPIError(`Error while creating the Contact List. data[0].id is undefined`, 'Criteo contact list creation error', 403);
    }
    return body.data[0].id;
};
exports.createContactList = createContactList;
//# sourceMappingURL=criteo-audiences.js.map