"use strict";
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);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
    return function (target, key) { decorator(target, key, paramIndex); }
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.PaymentsController = void 0;
const common_1 = require("@nestjs/common");
const swagger_1 = require("@nestjs/swagger");
const prisma_service_1 = require("../prisma/prisma.service");
const envelope_1 = require("../../common/envelope");
const public_decorator_1 = require("../../common/decorators/public.decorator");
const payments_service_1 = require("./payments.service");
const receipts_service_1 = require("./receipts.service");
const class_validator_1 = require("class-validator");
class CreatePaymentIntentDto {
}
__decorate([
    (0, class_validator_1.IsString)(),
    __metadata("design:type", String)
], CreatePaymentIntentDto.prototype, "purpose", void 0);
__decorate([
    (0, class_validator_1.IsString)(),
    __metadata("design:type", String)
], CreatePaymentIntentDto.prototype, "itemId", void 0);
__decorate([
    (0, class_validator_1.IsOptional)(),
    (0, class_validator_1.IsString)(),
    __metadata("design:type", String)
], CreatePaymentIntentDto.prototype, "gateway", void 0);
__decorate([
    (0, class_validator_1.IsOptional)(),
    (0, class_validator_1.IsString)(),
    __metadata("design:type", String)
], CreatePaymentIntentDto.prototype, "callbackUrl", void 0);
__decorate([
    (0, class_validator_1.IsOptional)(),
    (0, class_validator_1.IsString)(),
    __metadata("design:type", String)
], CreatePaymentIntentDto.prototype, "successUrl", void 0);
__decorate([
    (0, class_validator_1.IsOptional)(),
    (0, class_validator_1.IsString)(),
    __metadata("design:type", String)
], CreatePaymentIntentDto.prototype, "cancelUrl", void 0);
class VerifyPaymentDto {
}
__decorate([
    (0, class_validator_1.IsString)(),
    __metadata("design:type", String)
], VerifyPaymentDto.prototype, "gateway", void 0);
__decorate([
    (0, class_validator_1.IsOptional)(),
    (0, class_validator_1.IsString)(),
    __metadata("design:type", String)
], VerifyPaymentDto.prototype, "reference", void 0);
__decorate([
    (0, class_validator_1.IsOptional)(),
    (0, class_validator_1.IsString)(),
    __metadata("design:type", String)
], VerifyPaymentDto.prototype, "stripeSessionId", void 0);
__decorate([
    (0, class_validator_1.IsOptional)(),
    (0, class_validator_1.IsString)(),
    __metadata("design:type", String)
], VerifyPaymentDto.prototype, "flutterwaveTransactionId", void 0);
let PaymentsController = class PaymentsController {
    constructor(prisma, pay) {
        this.prisma = prisma;
        this.pay = pay;
        this.receipts = new receipts_service_1.ReceiptsService();
    }
    async createIntent(req, idempotencyKey, dto) {
        const userId = req.user.userId;
        const gateway = this.pay.normalizeGateway(dto.gateway);
        let amount = 0;
        let currency = 'NGN';
        let enrollmentId;
        let orderId;
        let email;
        if (dto.purpose === 'enrollment') {
            const enrollment = await this.prisma.enrollment.findFirst({
                where: { id: dto.itemId, userId },
                include: { course: true, user: true },
            });
            if (!enrollment)
                return (0, envelope_1.ok)({ error: 'Enrollment not found' });
            amount = enrollment.course.price;
            currency = enrollment.course.currency;
            enrollmentId = enrollment.id;
            email = enrollment.user.email ?? undefined;
        }
        else {
            const order = await this.prisma.order.findFirst({ where: { id: dto.itemId, userId }, include: { user: true } });
            if (!order)
                return (0, envelope_1.ok)({ error: 'Order not found' });
            amount = order.total;
            currency = order.currency;
            orderId = order.id;
            email = order.user.email ?? undefined;
        }
        const reference = idempotencyKey
            ? this.pay.deriveReferenceFromIdempotencyKey(`${userId}:${dto.purpose}:${dto.itemId}:${idempotencyKey}`)
            : `ALM_${Date.now()}_${Math.random().toString(16).slice(2)}`;
        const payment = await this.prisma.payment.upsert({
            where: { reference },
            create: { userId, gateway: gateway, amount, currency, reference, enrollmentId, orderId, status: 'pending' },
            update: { gateway: gateway, amount, currency, enrollmentId, orderId },
        });
        let authorizationUrl = null;
        if (gateway === 'stripe') {
            const successUrl = dto.successUrl ?? dto.callbackUrl ?? 'https://example.com/success';
            const cancelUrl = dto.cancelUrl ?? 'https://example.com/cancel';
            authorizationUrl = await this.pay.createStripeCheckout({
                amount,
                currency,
                reference: payment.reference,
                successUrl,
                cancelUrl,
                email,
            });
        }
        if (gateway === 'paystack') {
            if (!email)
                return (0, envelope_1.ok)({ error: 'Email is required for Paystack payments' });
            authorizationUrl = await this.pay.initPaystack({
                amount,
                email,
                reference: payment.reference,
                callbackUrl: dto.callbackUrl,
            });
        }
        if (gateway === 'flutterwave') {
            authorizationUrl = dto.callbackUrl ?? null;
        }
        return (0, envelope_1.ok)({ payment, checkout: { gateway, reference: payment.reference, authorizationUrl } });
    }
    async verify(req, dto) {
        const userId = req.user.userId;
        const gateway = this.pay.normalizeGateway(dto.gateway);
        let paid = false;
        let reference;
        if (gateway === 'paystack') {
            if (!dto.reference)
                return (0, envelope_1.ok)({ error: 'reference is required for paystack verification' });
            const v = await this.pay.verifyPaystackTransaction(dto.reference);
            paid = v.paid;
            reference = v.reference;
        }
        if (gateway === 'flutterwave') {
            if (!dto.flutterwaveTransactionId)
                return (0, envelope_1.ok)({ error: 'flutterwaveTransactionId is required' });
            const v = await this.pay.verifyFlutterwaveTransaction(dto.flutterwaveTransactionId);
            paid = v.paid;
            reference = v.reference;
        }
        if (gateway === 'stripe') {
            if (!dto.stripeSessionId)
                return (0, envelope_1.ok)({ error: 'stripeSessionId is required' });
            const v = await this.pay.verifyStripeCheckoutSession(dto.stripeSessionId);
            paid = v.paid;
            reference = v.reference;
        }
        if (!reference)
            return (0, envelope_1.ok)({ verified: false, paid: false });
        const payment = await this.prisma.payment.findFirst({ where: { reference, userId } });
        if (!payment)
            return (0, envelope_1.ok)({ verified: false, paid: false });
        if (paid)
            await this.markPaid(reference);
        const updated = await this.prisma.payment.findUnique({ where: { reference } });
        return (0, envelope_1.ok)({ verified: true, paid, payment: updated });
    }
    async myPayments(req, status) {
        const userId = req.user.userId;
        const where = { userId };
        if (status)
            where.status = status;
        const items = await this.prisma.payment.findMany({ where, orderBy: { createdAt: 'desc' } });
        return (0, envelope_1.ok)(items);
    }
    async receipt(req, reference, res) {
        const userId = req.user.userId;
        const payment = await this.prisma.payment.findFirst({
            where: { reference, userId },
            include: { user: true, enrollment: { include: { course: true } }, order: { include: { items: true } } },
        });
        if (!payment)
            return res.status(404).json({ success: false });
        const purpose = payment.enrollmentId ? 'Course Enrollment' : 'Bookstore Order';
        const itemLabel = payment.enrollment?.course?.title ?? `Order ${payment.orderId}`;
        const receiptNo = `ALM-RCPT-${payment.createdAt.getFullYear()}-${payment.reference.slice(-8)}`;
        const pdf = await this.receipts.createReceiptPdf({
            receiptNo,
            issuedAt: new Date(),
            payerName: payment.user.fullName,
            payerEmail: payment.user.email,
            reference: payment.reference,
            amount: payment.amount,
            currency: payment.currency,
            purpose,
            itemLabel,
            status: payment.status,
        });
        res.setHeader('Content-Type', 'application/pdf');
        res.setHeader('Content-Disposition', `inline; filename="${receiptNo}.pdf"`);
        return res.send(pdf);
    }
    async paystackWebhook(req, sig) {
        const valid = this.pay.verifyPaystackWebhook(req.rawBody, sig);
        if (!valid)
            return { received: true, verified: false };
        const event = req.body;
        if (event?.event === 'charge.success') {
            const reference = event?.data?.reference;
            if (reference)
                await this.markPaid(reference);
        }
        return { received: true, verified: true };
    }
    async flutterwaveWebhook(req, hash) {
        const valid = this.pay.verifyFlutterwaveWebhook(hash);
        if (!valid)
            return { received: true, verified: false };
        const event = req.body;
        const reference = event?.data?.tx_ref;
        const status = event?.data?.status;
        if (reference && (status === 'successful' || status === 'success'))
            await this.markPaid(reference);
        return { received: true, verified: true };
    }
    async stripeWebhook(req, sig) {
        if (!sig)
            return { received: true, verified: false };
        const event = this.pay.verifyStripeWebhook(req.rawBody, sig);
        if (event.type === 'checkout.session.completed') {
            const session = event.data.object;
            const reference = session?.metadata?.reference;
            if (reference)
                await this.markPaid(reference);
        }
        if (event.type === 'payment_intent.succeeded') {
            const pi = event.data.object;
            const reference = pi?.metadata?.reference;
            if (reference)
                await this.markPaid(reference);
        }
        return { received: true, verified: true };
    }
    async markPaid(reference) {
        const updated = await this.prisma.payment.updateMany({
            where: { reference, status: 'pending' },
            data: { status: 'paid' },
        });
        if (updated.count === 0)
            return;
        const payment = await this.prisma.payment.findUnique({ where: { reference } });
        if (!payment)
            return;
        if (payment.enrollmentId) {
            await this.prisma.enrollment.update({ where: { id: payment.enrollmentId }, data: { status: 'ACTIVE' } });
        }
        if (payment.orderId) {
            await this.prisma.order.update({ where: { id: payment.orderId }, data: { status: 'paid' } });
        }
    }
};
exports.PaymentsController = PaymentsController;
__decorate([
    (0, common_1.Post)('payments/intent'),
    __param(0, (0, common_1.Req)()),
    __param(1, (0, common_1.Headers)('idempotency-key')),
    __param(2, (0, common_1.Body)()),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object, Object, CreatePaymentIntentDto]),
    __metadata("design:returntype", Promise)
], PaymentsController.prototype, "createIntent", null);
__decorate([
    (0, common_1.Post)('payments/verify'),
    __param(0, (0, common_1.Req)()),
    __param(1, (0, common_1.Body)()),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object, VerifyPaymentDto]),
    __metadata("design:returntype", Promise)
], PaymentsController.prototype, "verify", null);
__decorate([
    (0, common_1.Get)('payments/my'),
    __param(0, (0, common_1.Req)()),
    __param(1, (0, common_1.Query)('status')),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object, String]),
    __metadata("design:returntype", Promise)
], PaymentsController.prototype, "myPayments", null);
__decorate([
    (0, common_1.Get)('payments/:reference/receipt'),
    __param(0, (0, common_1.Req)()),
    __param(1, (0, common_1.Param)('reference')),
    __param(2, (0, common_1.Res)()),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object, String, Object]),
    __metadata("design:returntype", Promise)
], PaymentsController.prototype, "receipt", null);
__decorate([
    (0, public_decorator_1.Public)(),
    (0, common_1.Post)('webhooks/paystack'),
    __param(0, (0, common_1.Req)()),
    __param(1, (0, common_1.Headers)('x-paystack-signature')),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object, String]),
    __metadata("design:returntype", Promise)
], PaymentsController.prototype, "paystackWebhook", null);
__decorate([
    (0, public_decorator_1.Public)(),
    (0, common_1.Post)('webhooks/flutterwave'),
    __param(0, (0, common_1.Req)()),
    __param(1, (0, common_1.Headers)('verif-hash')),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object, String]),
    __metadata("design:returntype", Promise)
], PaymentsController.prototype, "flutterwaveWebhook", null);
__decorate([
    (0, public_decorator_1.Public)(),
    (0, common_1.Post)('webhooks/stripe'),
    __param(0, (0, common_1.Req)()),
    __param(1, (0, common_1.Headers)('stripe-signature')),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object, String]),
    __metadata("design:returntype", Promise)
], PaymentsController.prototype, "stripeWebhook", null);
exports.PaymentsController = PaymentsController = __decorate([
    (0, swagger_1.ApiTags)('Payments'),
    (0, swagger_1.ApiBearerAuth)(),
    (0, common_1.Controller)(),
    __metadata("design:paramtypes", [prisma_service_1.PrismaService, payments_service_1.PaymentsService])
], PaymentsController);
//# sourceMappingURL=payments.controller.js.map