var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
import { IsBillingEnabled, NotificationSlackWebhookOnSubscriptionUpdate, } from "../EnvironmentConfig";
import logger from "../Utils/Logger";
import BaseService from "./BaseService";
import BillingService from "./BillingService";
import ProjectService from "./ProjectService";
import BadDataException from "../../Types/Exception/BadDataException";
import Email from "../../Types/Email";
import ObjectID from "../../Types/ObjectID";
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
import SlackUtil from "../Utils/Workspace/Slack/Slack";
import URL from "../../Types/API/URL";
export class NotificationService extends BaseService {
    constructor() {
        super();
    }
    async rechargeBalance(projectId, amountInUSD) {
        const project = await ProjectService.findOneById({
            id: projectId,
            select: {
                smsOrCallCurrentBalanceInUSDCents: true,
                enableAutoRechargeSmsOrCallBalance: true,
                enableSmsNotifications: true,
                autoRechargeSmsOrCallByBalanceInUSD: true,
                autoRechargeSmsOrCallWhenCurrentBalanceFallsInUSD: true,
                paymentProviderCustomerId: true,
                name: true,
                failedCallAndSMSBalanceChargeNotificationSentToOwners: true,
                sendInvoicesByEmail: true,
                financeAccountingEmail: true,
            },
            props: {
                isRoot: true,
            },
        });
        if (!project) {
            return 0;
        }
        try {
            if (!(await BillingService.hasPaymentMethods(project.paymentProviderCustomerId))) {
                if (!project.failedCallAndSMSBalanceChargeNotificationSentToOwners) {
                    await ProjectService.updateOneById({
                        data: {
                            failedCallAndSMSBalanceChargeNotificationSentToOwners: true,
                        },
                        id: project.id,
                        props: {
                            isRoot: true,
                        },
                    });
                    await ProjectService.sendEmailToProjectOwners(project.id, "ACTION REQUIRED: SMS and Call Recharge Failed for project - " +
                        (project.name || ""), `We have tried to recharge your SMS and Call balance for project - ${project.name || ""} and failed. We could not find a payment method for the project. Please add a payment method in Project Settings.`);
                }
                throw new BadDataException("No payment methods found for the project. Please add a payment method in Project Settings to continue.");
            }
            // recharge balance
            const updatedAmount = Math.floor((project.smsOrCallCurrentBalanceInUSDCents || 0) + amountInUSD * 100);
            // If the recharge is successful, then update the project balance.
            await BillingService.generateInvoiceAndChargeCustomer(project.paymentProviderCustomerId, "SMS or Call Balance Recharge", amountInUSD, {
                sendInvoiceByEmail: project.sendInvoicesByEmail || false,
                recipientEmails: project.financeAccountingEmail
                    ? Email.parseList(project.financeAccountingEmail)
                    : undefined,
                projectId: project.id || undefined,
            });
            await ProjectService.updateOneById({
                data: {
                    smsOrCallCurrentBalanceInUSDCents: updatedAmount,
                    failedCallAndSMSBalanceChargeNotificationSentToOwners: false, // reset this flag
                    lowCallAndSMSBalanceNotificationSentToOwners: false, // reset this flag
                    notEnabledSmsOrCallNotificationSentToOwners: false,
                },
                id: project.id,
                props: {
                    isRoot: true,
                },
            });
            await ProjectService.sendEmailToProjectOwners(project.id, "SMS and Call Recharge Successful for project - " +
                (project.name || ""), `We have successfully recharged your SMS and Call balance for project - ${project.name || ""} by ${amountInUSD} USD. Your current balance is ${updatedAmount / 100} USD.`);
            // Send Slack notification for balance refill
            this.sendBalanceRefillSlackNotification({
                project: project,
                amountInUSD: amountInUSD,
                currentBalanceInUSD: updatedAmount / 100,
            }).catch((error) => {
                logger.error("Error sending slack message for balance refill: " + error, { projectId: projectId === null || projectId === void 0 ? void 0 : projectId.toString() });
            });
            project.smsOrCallCurrentBalanceInUSDCents = updatedAmount;
            return updatedAmount;
        }
        catch (err) {
            await ProjectService.updateOneById({
                data: {
                    failedCallAndSMSBalanceChargeNotificationSentToOwners: true,
                },
                id: project.id,
                props: {
                    isRoot: true,
                },
            });
            await ProjectService.sendEmailToProjectOwners(project.id, "ACTION REQUIRED: SMS and Call Recharge Failed for project - " +
                (project.name || ""), `We have tried recharged your SMS and Call balance for project - ${project.name || ""} and failed. Please make sure your payment method is upto date and has sufficient balance. You can add new payment methods in Project Settings.`);
            logger.error(err, { projectId: projectId === null || projectId === void 0 ? void 0 : projectId.toString() });
            throw err;
        }
    }
    async rechargeIfBalanceIsLow(projectId, options) {
        let project = null;
        if (projectId && IsBillingEnabled) {
            // check payment methods.
            project = await ProjectService.findOneById({
                id: projectId,
                select: {
                    smsOrCallCurrentBalanceInUSDCents: true,
                    enableAutoRechargeSmsOrCallBalance: true,
                    autoRechargeSmsOrCallByBalanceInUSD: true,
                    autoRechargeSmsOrCallWhenCurrentBalanceFallsInUSD: true,
                },
                props: {
                    isRoot: true,
                },
            });
            const autoRechargeSmsOrCallWhenCurrentBalanceFallsInUSD = (options === null || options === void 0 ? void 0 : options.autoRechargeSmsOrCallWhenCurrentBalanceFallsInUSD) ||
                (project === null || project === void 0 ? void 0 : project.autoRechargeSmsOrCallWhenCurrentBalanceFallsInUSD) ||
                0;
            const autoRechargeSmsOrCallByBalanceInUSD = (options === null || options === void 0 ? void 0 : options.autoRechargeSmsOrCallByBalanceInUSD) ||
                (project === null || project === void 0 ? void 0 : project.autoRechargeSmsOrCallByBalanceInUSD) ||
                0;
            const enableAutoRechargeSmsOrCallBalance = options
                ? options.enableAutoRechargeSmsOrCallBalance
                : (project === null || project === void 0 ? void 0 : project.enableAutoRechargeSmsOrCallBalance) || false;
            if (!project) {
                return 0;
            }
            if (enableAutoRechargeSmsOrCallBalance &&
                autoRechargeSmsOrCallByBalanceInUSD &&
                autoRechargeSmsOrCallWhenCurrentBalanceFallsInUSD) {
                if ((project.smsOrCallCurrentBalanceInUSDCents || 0) / 100 <
                    autoRechargeSmsOrCallWhenCurrentBalanceFallsInUSD) {
                    const updatedAmount = await this.rechargeBalance(projectId, autoRechargeSmsOrCallByBalanceInUSD);
                    project.smsOrCallCurrentBalanceInUSDCents = updatedAmount;
                }
            }
        }
        return (project === null || project === void 0 ? void 0 : project.smsOrCallCurrentBalanceInUSDCents) || 0;
    }
    async sendBalanceRefillSlackNotification(data) {
        var _a, _b;
        const { project, amountInUSD, currentBalanceInUSD } = data;
        if (NotificationSlackWebhookOnSubscriptionUpdate) {
            const slackMessage = `*SMS and Call Balance Refilled:*
*Project Name:* ${((_a = project.name) === null || _a === void 0 ? void 0 : _a.toString()) || "N/A"}
*Project ID:* ${((_b = project.id) === null || _b === void 0 ? void 0 : _b.toString()) || "N/A"}
*Refill Amount:* $${amountInUSD} USD
*Current Balance:* $${currentBalanceInUSD} USD

${project.createdOwnerName && project.createdOwnerEmail ? `*Project Created By:* ${project.createdOwnerName.toString()} (${project.createdOwnerEmail.toString()})` : ""}`;
            SlackUtil.sendMessageToChannelViaIncomingWebhook({
                url: URL.fromString(NotificationSlackWebhookOnSubscriptionUpdate),
                text: slackMessage,
            }).catch((error) => {
                var _a;
                logger.error("Error sending slack message for balance refill: " + error, { projectId: (_a = project.id) === null || _a === void 0 ? void 0 : _a.toString() });
            });
        }
    }
}
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [ObjectID, Number]),
    __metadata("design:returntype", Promise)
], NotificationService.prototype, "rechargeBalance", null);
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [ObjectID, Object]),
    __metadata("design:returntype", Promise)
], NotificationService.prototype, "rechargeIfBalanceIsLow", null);
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object]),
    __metadata("design:returntype", Promise)
], NotificationService.prototype, "sendBalanceRefillSlackNotification", null);
export default new NotificationService();
//# sourceMappingURL=NotificationService.js.map