"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SQSService = void 0;
const aws_sdk_1 = require("aws-sdk");
const logger_1 = require("../utils/logger");
const flatted_1 = require("flatted");
class SQSService {
    config;
    sqsClient;
    sqsEnabled;
    maxNumberOfMessages;
    waitTimeSeconds;
    queueUrlsCache = new Map();
    constructor(config) {
        this.config = config;
        this.sqsEnabled = config.aws.sqs.enabled;
        this.maxNumberOfMessages = config.aws.sqs.maxNumberOfMessages;
        this.waitTimeSeconds = config.aws.sqs.waitTimeSeconds;
    }
    isSQSEnabled() {
        return this.sqsEnabled;
    }
    /**
     * Initialize the SQS client
     */
    init(context) {
        const childLogger = logger_1.logger.child({ context });
        if (this.sqsEnabled) {
            try {
                this.sqsClient = new aws_sdk_1.SQS({
                    region: this.config.aws.region,
                });
                childLogger.info('🚀 SQS client initialized');
            }
            catch (error) {
                childLogger.error({ error: error.message, sqsConfig: JSON.stringify(this.config.aws) }, '🚨 Could not initialize SQS client');
            }
        }
    }
    /**
     * Get the SQS queue URL, with caching
     */
    async getQueueUrl(queueName) {
        if (this.queueUrlsCache.has(queueName)) {
            return this.queueUrlsCache.get(queueName);
        }
        try {
            const sqsQueueUrl = await this.sqsClient.getQueueUrl({ QueueName: queueName }).promise();
            if (!sqsQueueUrl.QueueUrl) {
                throw new Error('SQS queue URL not found');
            }
            this.queueUrlsCache.set(queueName, sqsQueueUrl.QueueUrl);
            return sqsQueueUrl.QueueUrl;
        }
        catch (error) {
            logger_1.logger.error({ error: error.message, queueName }, '🚨 Could not get SQS queue URL');
            throw error;
        }
    }
    /**
     * Push a message into the specified SQS queue
     */
    async pushMessage(queueName, messageBody, childLogger, options) {
        if (!this.sqsEnabled || !this.sqsClient) {
            childLogger.error({ sqsEnabled: this.sqsEnabled }, '🚨 SQS not enabled or client not initialized.');
            return false;
        }
        try {
            const queueUrl = await this.getQueueUrl(queueName);
            const params = {
                QueueUrl: queueUrl,
                MessageBody: messageBody,
            };
            if (options?.messageGroupId) {
                params.MessageGroupId = options.messageGroupId;
            }
            if (options?.messageDeduplicationId) {
                params.MessageDeduplicationId = options.messageDeduplicationId;
            }
            if (options?.messageAttributes) {
                params.MessageAttributes = options.messageAttributes;
            }
            await this.sqsClient.sendMessage(params).promise();
            childLogger.debug({ queueName, MessageAttributes: JSON.stringify(params.MessageAttributes) }, 'Pushed message to SQS queue.');
            return true;
        }
        catch (error) {
            childLogger.error({ error: error.message, queueName }, '🚨 Could not push message to SQS');
            return false;
        }
    }
    /**
     * Retrieve messages from the specified SQS queue
     */
    async retrieveMessages(queueName, childLogger) {
        if (!this.sqsEnabled || !this.sqsClient) {
            childLogger.error({ sqsEnabled: this.sqsEnabled }, '🚨 SQS not enabled or client not initialized.');
            return [];
        }
        const prefixDLQ = queueName.includes('DLQ') ? 'DLQ' : '';
        try {
            const queueUrl = await this.getQueueUrl(queueName);
            const params = {
                QueueUrl: queueUrl,
                MaxNumberOfMessages: this.maxNumberOfMessages,
                WaitTimeSeconds: this.waitTimeSeconds,
                MessageAttributeNames: ['All'], // get attached msg attributes if available, e.g.: networkId, eventName, orderId
                AttributeNames: ['MessageGroupId'],
            };
            const response = await this.sqsClient.receiveMessage(params).promise();
            const messages = response.Messages || [];
            childLogger.debug({ count: messages.length, queueName }, `Retrieved messages from ${prefixDLQ} SQS queue.`);
            return messages;
        }
        catch (error) {
            childLogger.error({ error: error.message, queueName }, `🚨 Error retrieving messages from ${prefixDLQ} SQS`);
            return [];
        }
    }
    /**
     * Delete a message from the specified SQS queue after processing
     */
    async deleteMessage(queueName, receiptHandle, childLogger, elapsedTimeSec = 0) {
        if (!this.sqsEnabled) {
            childLogger.error({ sqsEnabled: this.sqsEnabled }, '🚨 SQS not enabled or client not initialized.');
            return false;
        }
        try {
            const queueUrl = await this.getQueueUrl(queueName);
            const params = {
                QueueUrl: queueUrl,
                ReceiptHandle: receiptHandle,
            };
            await this.sqsClient.deleteMessage(params).promise();
            return true;
        }
        catch (error) {
            childLogger.error({ err: (0, flatted_1.stringify)(error), error: error.message, queueName, elapsedTimeSec }, '🚨 Error deleting message from SQS');
            return false;
        }
    }
    async increaseVisibilityTimeout(queueName, receiptHandle, visibilityTimeout, childLogger) {
        if (!this.sqsEnabled || !this.sqsClient) {
            childLogger.error({ sqsEnabled: this.sqsEnabled }, '🚨 SQS not enabled or client not initialized.');
            return;
        }
        try {
            const queueUrl = await this.getQueueUrl(queueName);
            const params = {
                QueueUrl: queueUrl,
                ReceiptHandle: receiptHandle,
                VisibilityTimeout: visibilityTimeout,
            };
            await this.sqsClient.changeMessageVisibility(params).promise();
            childLogger.debug({ queueName }, 'Increased visibility timeout for message in SQS queue.');
        }
        catch (error) {
            childLogger.error({ error: error.message, queueName }, '🚨 Error increasing visibility timeout for message in SQS');
        }
    }
}
exports.SQSService = SQSService;
//# sourceMappingURL=sqs.service.js.map