"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.send = exports.validateIamRoleArnFormat = void 0;
const client_kinesis_1 = require("@aws-sdk/client-kinesis");
const sts_1 = require("../../lib/AWS/sts");
const utils_1 = require("../../lib/AWS/utils");
const actions_core_1 = require("@segment/actions-core");
const validateIamRoleArnFormat = (arn) => {
    const iamRoleArnRegex = /^arn:aws:iam::\d{12}:role\/[A-Za-z0-9+=,.@_\-/]+$/;
    return iamRoleArnRegex.test(arn);
};
exports.validateIamRoleArnFormat = validateIamRoleArnFormat;
const transformPayloads = (payloads) => {
    return payloads.map((record) => ({
        Data: Buffer.from(JSON.stringify(record.payload)),
        PartitionKey: record.partitionKey
    }));
};
const createKinesisClient = async (iamRoleArn, iamExternalId, awsRegion) => {
    const credentials = await (0, sts_1.assumeRole)(iamRoleArn, iamExternalId, utils_1.APP_AWS_REGION);
    return new client_kinesis_1.KinesisClient({
        region: awsRegion,
        credentials: credentials
    });
};
const send = async (settings, payloads, statsContext, logger, signal) => {
    const { iamRoleArn, iamExternalId } = settings;
    const { streamName, awsRegion } = payloads[0];
    const entries = transformPayloads(payloads);
    statsContext?.statsClient?.histogram('actions_kinesis.batch_size', entries?.length, statsContext?.tags);
    statsContext?.statsClient?.incr('actions_kinesis.request_hit', 1, statsContext?.tags);
    try {
        const client = await createKinesisClient(iamRoleArn, iamExternalId, awsRegion);
        const command = new client_kinesis_1.PutRecordsCommand({
            StreamName: streamName,
            Records: entries
        });
        const response = await client.send(command, { abortSignal: signal });
        const multiResp = handleMultiStatusResponse(response, statsContext, payloads);
        return multiResp;
    }
    catch (error) {
        if (error.name === 'AbortError') {
            throw new actions_core_1.RequestTimeoutError();
        }
        logger?.crit('Failed to send batch to Kinesis:', error);
        handleError(error, statsContext);
    }
    return Promise.resolve(new actions_core_1.MultiStatusResponse());
};
exports.send = send;
const handleError = (error, statsContext) => {
    if (error?.name === 'AccessDeniedException') {
        statsContext?.statsClient?.incr('actions_kinesis.access_denied_exception', 1, statsContext?.tags);
        throw new actions_core_1.IntegrationError(`Access denied. Please check that the provided IAM Role has the necessary permissions to access Kinesis.`, 'ACCESS_DENIED', 403);
    }
    statsContext?.statsClient?.incr('actions_kinesis.error', 1, statsContext?.tags);
    throw new actions_core_1.IntegrationError(`Failed to send batch to Kinesis: ${error?.message}`, 'DEPENDENCY_ERROR', 500);
};
const ERROR_CODE_STATUS_MAP = {
    ThrottlingException: 429,
    LimitExceededException: 429,
    ProvisionedThroughputExceededException: 429,
    KMSThrottlingException: 429,
    AccessDeniedException: 502,
    AccessDenied: 502,
    KMSAccessDeniedException: 403,
    KMSOptInRequired: 403,
    ExpiredTokenException: 511,
    IDPRejectedClaimException: 511,
    InvalidIdentityTokenException: 511,
    IDPCommunicationErrorException: 503,
    InvalidAuthorizationMessageException: 400,
    MalformedPolicyDocumentException: 400,
    PackedPolicyTooLargeException: 400,
    ValidationException: 400,
    InvalidArgumentException: 400,
    InvalidParameter: 400,
    RegionDisabledException: 403,
    ResourceNotFoundException: 404,
    KMSNotFoundException: 404,
    ResourceInUseException: 409,
    KMSInvalidStateException: 409,
    InternalFailureException: 503,
    KMSDisabledException: 503
};
const convertErrorCodeToStatus = (code) => {
    if (!code) {
        return 500;
    }
    const normalizedCode = code.trim();
    return ERROR_CODE_STATUS_MAP[normalizedCode] ?? 500;
};
const handleMultiStatusResponse = (response, statsContext, payloads) => {
    const multiStatusResponse = new actions_core_1.MultiStatusResponse();
    const { FailedRecordCount, Records } = response;
    if (!FailedRecordCount || FailedRecordCount == 0) {
        statsContext?.statsClient?.incr('actions_kinesis.successful_record_count', Records?.length || 0, statsContext?.tags);
        Records?.forEach((record, index) => {
            multiStatusResponse.setSuccessResponseAtIndex(index, {
                status: 200,
                body: record,
                sent: payloads[index]
            });
        });
        return multiStatusResponse;
    }
    statsContext?.statsClient?.incr('actions_kinesis.failed_record_count', FailedRecordCount, statsContext?.tags);
    Records?.forEach((record, index) => {
        if (record.ErrorCode) {
            const statusCode = convertErrorCodeToStatus(record.ErrorCode);
            multiStatusResponse.setErrorResponseAtIndex(index, {
                status: statusCode,
                errormessage: record.ErrorMessage
            });
            const errorCode = record.ErrorCode || 'UnknownError';
            statsContext?.statsClient?.incr(`actions_kinesis.error.${errorCode}`, 1, statsContext?.tags);
        }
        else {
            multiStatusResponse.setSuccessResponseAtIndex(index, {
                status: 200,
                body: record,
                sent: payloads[index]
            });
            statsContext?.statsClient?.incr('actions_kinesis.successful_record_count', 1, statsContext?.tags);
        }
    });
    return multiStatusResponse;
};
//# sourceMappingURL=utils.js.map