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 AIBillingService extends BaseService {
    constructor() {
        super();
    }
    async rechargeBalance(projectId, amountInUSD) {
        if (!IsBillingEnabled) {
            throw new BadDataException("Billing is not enabled");
        }
        const project = await ProjectService.findOneById({
            id: projectId,
            select: {
                aiCurrentBalanceInUSDCents: true,
                enableAutoRechargeAiBalance: true,
                enableAi: true,
                autoAiRechargeByBalanceInUSD: true,
                autoRechargeAiWhenCurrentBalanceFallsInUSD: true,
                paymentProviderCustomerId: true,
                name: true,
                failedAiBalanceChargeNotificationSentToOwners: true,
                sendInvoicesByEmail: true,
                financeAccountingEmail: true,
            },
            props: {
                isRoot: true,
            },
        });
        if (!project) {
            return 0;
        }
        try {
            if (!(await BillingService.hasPaymentMethods(project.paymentProviderCustomerId))) {
                if (!project.failedAiBalanceChargeNotificationSentToOwners) {
                    await ProjectService.updateOneById({
                        data: {
                            failedAiBalanceChargeNotificationSentToOwners: true,
                        },
                        id: project.id,
                        props: {
                            isRoot: true,
                        },
                    });
                    await ProjectService.sendEmailToProjectOwners(project.id, "ACTION REQUIRED: AI Balance Recharge Failed for project - " +
                        (project.name || ""), `We have tried to recharge your AI 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.aiCurrentBalanceInUSDCents || 0) + amountInUSD * 100);
            // If the recharge is successful, then update the project balance.
            await BillingService.generateInvoiceAndChargeCustomer(project.paymentProviderCustomerId, "AI Balance Recharge", amountInUSD, {
                sendInvoiceByEmail: project.sendInvoicesByEmail || false,
                recipientEmails: project.financeAccountingEmail
                    ? Email.parseList(project.financeAccountingEmail)
                    : undefined,
                projectId: project.id || undefined,
            });
            await ProjectService.updateOneById({
                data: {
                    aiCurrentBalanceInUSDCents: updatedAmount,
                    failedAiBalanceChargeNotificationSentToOwners: false, // reset this flag
                    lowAiBalanceNotificationSentToOwners: false, // reset this flag
                    notEnabledAiNotificationSentToOwners: false,
                },
                id: project.id,
                props: {
                    isRoot: true,
                },
            });
            await ProjectService.sendEmailToProjectOwners(project.id, "AI Balance Recharge Successful for project - " + (project.name || ""), `We have successfully recharged your AI 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 AI balance refill: " + error);
            });
            project.aiCurrentBalanceInUSDCents = updatedAmount;
            return updatedAmount;
        }
        catch (err) {
            await ProjectService.updateOneById({
                data: {
                    failedAiBalanceChargeNotificationSentToOwners: true,
                },
                id: project.id,
                props: {
                    isRoot: true,
                },
            });
            await ProjectService.sendEmailToProjectOwners(project.id, "ACTION REQUIRED: AI Balance Recharge Failed for project - " +
                (project.name || ""), `We have tried to recharge your AI balance for project - ${project.name || ""} and failed. Please make sure your payment method is up to date and has sufficient balance. You can add new payment methods in Project Settings.`);
            logger.error(err);
            throw err;
        }
    }
    async rechargeIfBalanceIsLow(projectId, options) {
        let project = null;
        if (projectId && IsBillingEnabled) {
            // check payment methods.
            project = await ProjectService.findOneById({
                id: projectId,
                select: {
                    aiCurrentBalanceInUSDCents: true,
                    enableAutoRechargeAiBalance: true,
                    autoAiRechargeByBalanceInUSD: true,
                    autoRechargeAiWhenCurrentBalanceFallsInUSD: true,
                },
                props: {
                    isRoot: true,
                },
            });
            const autoRechargeAiWhenCurrentBalanceFallsInUSD = (options === null || options === void 0 ? void 0 : options.autoRechargeAiWhenCurrentBalanceFallsInUSD) ||
                (project === null || project === void 0 ? void 0 : project.autoRechargeAiWhenCurrentBalanceFallsInUSD) ||
                0;
            const autoAiRechargeByBalanceInUSD = (options === null || options === void 0 ? void 0 : options.autoAiRechargeByBalanceInUSD) ||
                (project === null || project === void 0 ? void 0 : project.autoAiRechargeByBalanceInUSD) ||
                0;
            const enableAutoRechargeAiBalance = options
                ? options.enableAutoRechargeAiBalance
                : (project === null || project === void 0 ? void 0 : project.enableAutoRechargeAiBalance) || false;
            if (!project) {
                return 0;
            }
            if (enableAutoRechargeAiBalance &&
                autoAiRechargeByBalanceInUSD &&
                autoRechargeAiWhenCurrentBalanceFallsInUSD) {
                if ((project.aiCurrentBalanceInUSDCents || 0) / 100 <
                    autoRechargeAiWhenCurrentBalanceFallsInUSD) {
                    const updatedAmount = await this.rechargeBalance(projectId, autoAiRechargeByBalanceInUSD);
                    project.aiCurrentBalanceInUSDCents = updatedAmount;
                }
            }
        }
        return (project === null || project === void 0 ? void 0 : project.aiCurrentBalanceInUSDCents) || 0;
    }
    async sendBalanceRefillSlackNotification(data) {
        var _a, _b;
        const { project, amountInUSD, currentBalanceInUSD } = data;
        if (NotificationSlackWebhookOnSubscriptionUpdate) {
            const slackMessage = `*AI 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) => {
                logger.error("Error sending slack message for AI balance refill: " + error);
            });
        }
    }
}
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [ObjectID, Number]),
    __metadata("design:returntype", Promise)
], AIBillingService.prototype, "rechargeBalance", null);
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [ObjectID, Object]),
    __metadata("design:returntype", Promise)
], AIBillingService.prototype, "rechargeIfBalanceIsLow", null);
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object]),
    __metadata("design:returntype", Promise)
], AIBillingService.prototype, "sendBalanceRefillSlackNotification", null);
export default new AIBillingService();
//# sourceMappingURL=AIBillingService.js.map