import { IsBillingEnabled } from "../EnvironmentConfig";
import UserMiddleware from "../Middleware/UserAuthorization";
import BillingInvoiceService from "../Services/BillingInvoiceService";
import BillingService from "../Services/BillingService";
import ProjectService from "../Services/ProjectService";
import Response from "../Utils/Response";
import BaseAPI from "./BaseAPI";
import BaseModel from "../../Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel";
import BadDataException from "../../Types/Exception/BadDataException";
import Permission from "../../Types/Permission";
import BillingInvoice, { InvoiceStatus, } from "../../Models/DatabaseModels/BillingInvoice";
export default class UserAPI extends BaseAPI {
    constructor() {
        var _a;
        super(BillingInvoice, BillingInvoiceService);
        this.router.post(`${(_a = new this.entityType().getCrudApiPath()) === null || _a === void 0 ? void 0 : _a.toString()}/pay`, UserMiddleware.getUserMiddleware, async (req, res, next) => {
            var _a;
            try {
                if (!IsBillingEnabled) {
                    throw new BadDataException("Billing is not enabled for this server");
                }
                if (req.body["projectId"]) {
                    throw new BadDataException("projectId is required in request body");
                }
                const userPermissions = (await this.getPermissionsForTenant(req)).filter((permission) => {
                    return (permission.permission.toString() ===
                        Permission.ProjectOwner.toString() ||
                        permission.permission.toString() ===
                            Permission.EditInvoices.toString());
                });
                if (userPermissions.length === 0 &&
                    !((_a = req.userAuthorization) === null || _a === void 0 ? void 0 : _a.isMasterAdmin)) {
                    throw new BadDataException(`You need ${Permission.ProjectOwner} or ${Permission.EditInvoices} permission to pay invoices.`);
                }
                const project = await ProjectService.findOneById({
                    id: this.getTenantId(req),
                    props: {
                        isRoot: true,
                    },
                    select: {
                        _id: true,
                        paymentProviderCustomerId: true,
                        paymentProviderSubscriptionId: true,
                        paymentProviderMeteredSubscriptionId: true,
                    },
                });
                if (!project) {
                    throw new BadDataException("Project not found");
                }
                if (!project.paymentProviderCustomerId) {
                    throw new BadDataException("Payment Provider customer not found");
                }
                if (!project.paymentProviderSubscriptionId) {
                    throw new BadDataException("Payment Provider subscription not found");
                }
                const body = req.body;
                const item = BaseModel.fromJSON(body["data"], this.entityType);
                if (!item.paymentProviderInvoiceId) {
                    throw new BadDataException("Invoice ID not found");
                }
                if (!item.paymentProviderCustomerId) {
                    throw new BadDataException("Customer ID not found");
                }
                let invoice = null;
                try {
                    invoice = await BillingService.payInvoice(item.paymentProviderCustomerId, item.paymentProviderInvoiceId);
                }
                catch (err) {
                    invoice = await BillingService.getInvoice(item.paymentProviderCustomerId, item.paymentProviderInvoiceId);
                    // check if this invoice needs more authentication like 3ds secure.
                    if (invoice.status === InvoiceStatus.Open &&
                        invoice.paymentIntentId) {
                        const paymentIntentId = invoice.paymentIntentId;
                        const clientSecret = await BillingService.getPaymentIntentClientSecret(paymentIntentId);
                        return Response.sendJsonObjectResponse(req, res, {
                            clientSecret: clientSecret,
                        });
                    }
                    // otherwise we have no idea what went wrong and throw an error.
                    throw err;
                }
                // save updated status.
                await this.service.updateOneBy({
                    query: {
                        paymentProviderInvoiceId: invoice.id,
                    },
                    props: {
                        isRoot: true,
                        ignoreHooks: true,
                    },
                    data: {
                        status: invoice.status,
                    },
                });
                await BillingInvoiceService.refreshSubscriptionStatus({
                    projectId: project.id,
                });
                return Response.sendEmptySuccessResponse(req, res);
            }
            catch (err) {
                next(err);
            }
        });
    }
}
//# sourceMappingURL=BillingInvoiceAPI.js.map