"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.handleUpdate = exports.sendUpdateRequest = exports.createUpdateRequest = exports.bulkUploaderResponseHandler = exports.assembleRawOps = exports.buildHeaders = exports.getAuthToken = exports.getAuthSettings = void 0;
const actions_core_1 = require("@segment/actions-core");
const constants_1 = require("./constants");
const protobuf_1 = require("@bufbuild/protobuf");
const protofile_1 = require("./proto/protofile");
const getAuthSettings = () => {
    return {
        refresh_token: process.env.ACTIONS_DISPLAY_VIDEO_360_REFRESH_TOKEN,
        client_id: process.env.ACTIONS_DISPLAY_VIDEO_360_CLIENT_ID,
        client_secret: process.env.ACTIONS_DISPLAY_VIDEO_360_CLIENT_SECRET
    };
};
exports.getAuthSettings = getAuthSettings;
const getAuthToken = async (request, settings) => {
    if (!settings.refresh_token) {
        throw new actions_core_1.IntegrationError('Refresh token is missing', 'INVALID_REQUEST_DATA', 400);
    }
    const { data } = await request(constants_1.OAUTH_URL, {
        method: 'POST',
        body: new URLSearchParams({
            refresh_token: settings.refresh_token,
            client_id: settings.client_id,
            client_secret: settings.client_secret,
            grant_type: 'refresh_token'
        })
    });
    return data.access_token;
};
exports.getAuthToken = getAuthToken;
const buildHeaders = (audienceSettings, accessToken) => {
    if (!audienceSettings || !accessToken) {
        throw new actions_core_1.IntegrationError('Bad Request', 'INVALID_REQUEST_DATA', 400);
    }
    return {
        Authorization: `Bearer ${accessToken}`,
        'Content-Type': 'application/json',
        'Login-Customer-Id': `products/DATA_PARTNER/customers/${constants_1.SEGMENT_DMP_ID}`,
        'Linked-Customer-Id': `products/${audienceSettings.accountType}/customers/${audienceSettings?.advertiserId}`
    };
};
exports.buildHeaders = buildHeaders;
const assembleRawOps = (payload, operation) => {
    const rawOperations = [];
    const audienceId = parseInt(payload.external_audience_id.split('/').pop() || '-1');
    const isDelete = operation === 'remove';
    if (payload.google_gid) {
        rawOperations.push({
            UserId: payload.google_gid,
            UserIdType: protofile_1.UserIdType.GOOGLE_USER_ID,
            UserListId: audienceId,
            Delete: isDelete
        });
    }
    if (payload.mobile_advertising_id) {
        const isIDFA = payload.mobile_advertising_id.includes('-');
        rawOperations.push({
            UserId: payload.mobile_advertising_id,
            UserIdType: isIDFA ? protofile_1.UserIdType.IDFA : protofile_1.UserIdType.ANDROID_ADVERTISING_ID,
            UserListId: audienceId,
            Delete: isDelete
        });
    }
    if (payload.partner_provided_id) {
        rawOperations.push({
            UserId: payload.partner_provided_id,
            UserIdType: protofile_1.UserIdType.PARTNER_PROVIDED_ID,
            UserListId: audienceId,
            Delete: isDelete
        });
    }
    return rawOperations;
};
exports.assembleRawOps = assembleRawOps;
const handleErrorCode = (errorCodeString, r, statsName, statsContext) => {
    if (errorCodeString === 'PARTIAL_SUCCESS') {
        statsContext?.statsClient.incr(`${statsName}.error.PARTIAL_SUCCESS`, 1, statsContext?.tags);
        r.errors?.forEach((e) => {
            if (e.errorCode) {
                statsContext?.statsClient.incr(`${statsName}.error.${protofile_1.ErrorCode[e.errorCode]}`, 1, statsContext?.tags);
            }
        });
    }
    else {
        statsContext?.statsClient.incr(`${statsName}.error.${errorCodeString}`, 1, statsContext?.tags);
    }
};
const bulkUploaderResponseHandler = async (response, statsName, statsContext) => {
    if (!response || !response.body) {
        throw new actions_core_1.IntegrationError(`Something went wrong unpacking the protobuf response`, 'INVALID_REQUEST_DATA', 400);
    }
    const buffer = await response.arrayBuffer();
    const protobufResponse = Buffer.from(buffer);
    const r = (0, protobuf_1.fromBinary)(protofile_1.UpdateUsersDataResponseSchema, protobufResponse);
    const errorCode = r.status;
    const errorCodeString = protofile_1.ErrorCode[errorCode] || 'UNKNOWN_ERROR';
    if (errorCodeString === 'NO_ERROR' || response.status === 200) {
        statsContext?.statsClient.incr(`${statsName}.success`, 1, statsContext?.tags);
    }
    else {
        handleErrorCode(errorCodeString, r, statsName, statsContext);
        if (errorCode === protofile_1.ErrorCode.INTERNAL_ERROR) {
            statsContext?.statsClient.incr(`${statsName}.error.INTERNAL_ERROR`, 1, statsContext?.tags);
            throw new actions_core_1.IntegrationError('Bulk Uploader Internal Error', 'INTERNAL_SERVER_ERROR', 500);
        }
    }
};
exports.bulkUploaderResponseHandler = bulkUploaderResponseHandler;
const createUpdateRequest = (payload, operation) => {
    const updateRequest = (0, protobuf_1.create)(protofile_1.UpdateUsersDataRequestSchema, {});
    payload.forEach((p) => {
        const rawOps = (0, exports.assembleRawOps)(p, operation);
        rawOps.forEach((rawOp) => {
            const op = (0, protobuf_1.create)(protofile_1.UserDataOperationSchema, {
                userId: rawOp.UserId,
                userIdType: rawOp.UserIdType,
                userListId: BigInt(rawOp.UserListId),
                delete: rawOp.Delete
            });
            if (!op) {
                throw new Error('Unable to create UserDataOperation');
            }
            updateRequest.ops.push(op);
        });
    });
    updateRequest.processConsent = true;
    return updateRequest;
};
exports.createUpdateRequest = createUpdateRequest;
const sendUpdateRequest = async (request, updateRequest, statsName, statsContext) => {
    const binaryOperation = (0, protobuf_1.toBinary)(protofile_1.UpdateUsersDataRequestSchema, updateRequest);
    try {
        const response = await request(constants_1.USER_UPLOAD_ENDPOINT, {
            headers: { 'Content-Type': 'application/octet-stream' },
            body: binaryOperation,
            method: 'POST'
        });
        await (0, exports.bulkUploaderResponseHandler)(response, statsName, statsContext);
    }
    catch (error) {
        if (error.response?.status === 500) {
            throw new actions_core_1.IntegrationError(error.response?.message ?? error.message, 'INTERNAL_SERVER_ERROR', 500);
        }
        await (0, exports.bulkUploaderResponseHandler)(error.response, statsName, statsContext);
    }
};
exports.sendUpdateRequest = sendUpdateRequest;
const handleUpdate = async (request, payload, operation, statsContext) => {
    const statsName = operation === 'add' ? 'addToAudience' : 'removeFromAudience';
    statsContext?.statsClient?.incr(`${statsName}.call`, 1, statsContext?.tags);
    const updateRequest = (0, exports.createUpdateRequest)(payload, operation);
    if (updateRequest.ops.length !== 0) {
        await (0, exports.sendUpdateRequest)(request, updateRequest, statsName, statsContext);
    }
    else {
        statsContext?.statsClient.incr(`${statsName}.discard`, 1, statsContext?.tags);
    }
    return {
        status: 200
    };
};
exports.handleUpdate = handleUpdate;
//# sourceMappingURL=shared.js.map