"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.PaymentService = void 0;
const database_1 = __importDefault(require("../../../config/database"));
const payment_gateway_factory_1 = require("./payment-gateway.factory");
const logger_1 = require("../../../config/logger");
class PaymentService {
    /**
     * 1. CREATE PAYMENT ORDER
     */
    static async initiatePayment(orderId, gateway, userId, method = 'UPI') {
        const order = await database_1.default.order.findUnique({
            where: { id: orderId },
            include: { user: true },
        });
        if (!order) {
            throw new Error('Order not found');
        }
        const gatewayClient = await payment_gateway_factory_1.PaymentGatewayFactory.getGateway(gateway);
        const gatewayOrder = await gatewayClient.createOrder(order);
        // DB Upsert payment
        const payment = await database_1.default.payment.upsert({
            where: { orderId: order.id },
            update: {
                gateway: gateway.toUpperCase(),
                gatewayOrderId: gatewayOrder.gatewayOrderId,
                amount: order.grandTotal,
                paymentMethod: method,
                status: 'PENDING',
            },
            create: {
                orderId: order.id,
                userId: userId,
                gateway: gateway.toUpperCase(),
                gatewayOrderId: gatewayOrder.gatewayOrderId,
                amount: order.grandTotal,
                paymentMethod: method,
                status: 'PENDING',
            },
        });
        // Create Payment Attempt Log
        await database_1.default.paymentAttempt.create({
            data: {
                paymentId: payment.id,
                gateway: gateway.toUpperCase(),
                amount: order.grandTotal,
                gatewayOrderId: gatewayOrder.gatewayOrderId,
                status: 'PENDING',
            },
        });
        // Create Audit Log
        await database_1.default.paymentAudit.create({
            data: {
                paymentId: payment.id,
                action: 'INITIATED',
                statusFrom: 'CREATED',
                statusTo: 'PENDING',
                performedBy: 'USER',
                details: `Payment process initiated via ${gateway}`,
            },
        });
        const checkout = await gatewayClient.createCheckout(gatewayOrder);
        return {
            paymentId: payment.id,
            gatewayOrderId: gatewayOrder.gatewayOrderId,
            amount: Number(order.grandTotal),
            currency: 'INR',
            ...checkout,
        };
    }
    /**
     * 2. VERIFY PAYMENT (SERVER-SIDE SIGNATURE CHECK)
     */
    static async verifyPayment(orderId, payload) {
        const payment = await database_1.default.payment.findUnique({
            where: { orderId },
            include: { order: true },
        });
        if (!payment) {
            throw new Error('Payment record not found');
        }
        const gatewayClient = await payment_gateway_factory_1.PaymentGatewayFactory.getGateway(payment.gateway);
        const verification = await gatewayClient.verifyPayment(payload);
        if (verification.success) {
            // Update Payment Status to SUCCESS
            await database_1.default.$transaction([
                database_1.default.payment.update({
                    where: { id: payment.id },
                    data: {
                        status: 'SUCCESS',
                        gatewayPaymentId: verification.gatewayPaymentId,
                        gatewayTransactionId: verification.gatewayTransactionId,
                    },
                }),
                database_1.default.order.update({
                    where: { id: orderId },
                    data: { status: 'PROCESSING' },
                }),
                database_1.default.paymentAudit.create({
                    data: {
                        paymentId: payment.id,
                        action: 'VERIFY_SUCCESS',
                        statusFrom: 'PENDING',
                        statusTo: 'SUCCESS',
                        performedBy: 'SYSTEM',
                        details: `Signature verification succeeded. Payment ID: ${verification.gatewayPaymentId}`,
                    },
                }),
            ]);
            // Automatically generate Tax Invoice
            await this.generateInvoice(payment.id);
            logger_1.logger.info(`Payment verified for order ${orderId}, txn: ${verification.gatewayPaymentId}`);
        }
        else {
            await database_1.default.$transaction([
                database_1.default.payment.update({
                    where: { id: payment.id },
                    data: { status: 'FAILED' },
                }),
                database_1.default.paymentAudit.create({
                    data: {
                        paymentId: payment.id,
                        action: 'VERIFY_FAILED',
                        statusFrom: 'PENDING',
                        statusTo: 'FAILED',
                        performedBy: 'SYSTEM',
                        details: verification.message || 'Signature check failed',
                    },
                }),
            ]);
        }
        return verification;
    }
    /**
     * 3. REFUND PROCESS (ADMIN)
     */
    static async processRefund(paymentId, amount, reason) {
        const payment = await database_1.default.payment.findUnique({
            where: { id: paymentId },
        });
        if (!payment) {
            throw new Error('Payment record not found');
        }
        if (payment.status !== 'SUCCESS') {
            throw new Error('Only successful payments can be refunded');
        }
        const gatewayClient = await payment_gateway_factory_1.PaymentGatewayFactory.getGateway(payment.gateway);
        const refundRes = await gatewayClient.refundPayment(payment.gatewayPaymentId || '', amount, reason);
        if (refundRes.success) {
            await database_1.default.$transaction([
                database_1.default.payment.update({
                    where: { id: payment.id },
                    data: { status: 'REFUNDED' },
                }),
                database_1.default.order.update({
                    where: { id: payment.orderId },
                    data: { status: 'RETURNED' },
                }),
                database_1.default.refund.create({
                    data: {
                        paymentId: payment.id,
                        gatewayRefundId: refundRes.gatewayRefundId,
                        amount: amount,
                        status: 'SUCCESS',
                        reason,
                        processedAt: new Date(),
                    },
                }),
                database_1.default.paymentAudit.create({
                    data: {
                        paymentId: payment.id,
                        action: 'REFUND_SUCCESS',
                        statusFrom: 'SUCCESS',
                        statusTo: 'REFUNDED',
                        performedBy: 'ADMIN',
                        details: `Refund processed successfully. Refund ID: ${refundRes.gatewayRefundId}`,
                    },
                }),
            ]);
            logger_1.logger.info(`Refund succeeded for payment: ${paymentId}, amount: ₹${amount}`);
        }
        return refundRes;
    }
    /**
     * 4. GENERATE INVOICE
     */
    static async generateInvoice(paymentId) {
        const payment = await database_1.default.payment.findUnique({
            where: { id: paymentId },
            include: {
                order: {
                    include: {
                        user: true,
                        shippingAddress: true,
                        items: { include: { book: true } },
                    },
                },
            },
        });
        if (!payment)
            throw new Error('Payment not found');
        const subtotal = Number(payment.order.totalAmount);
        const grandTotal = Number(payment.order.grandTotal);
        const gstRate = 5.0; // 5% standard GST on books
        const gstAmount = Math.round((subtotal * gstRate) / 100);
        const invoiceNumber = `INV-${payment.order.orderNumber}`;
        const invoice = await database_1.default.invoice.create({
            data: {
                paymentId: payment.id,
                invoiceNumber,
                gstin: '07AAAAA0000A1Z5',
                gstRate,
                gstAmount,
                subtotal,
                grandTotal,
                pdfUrl: `/invoice/download/${invoiceNumber}`,
            },
        });
        return invoice;
    }
    /**
     * 5. HANDLE WEBHOOKS (IDEMPOTENT & SECURE)
     */
    static async handleWebhook(gateway, payload, signature) {
        // Prevent duplicate webhook executions (idempotency check)
        const eventId = payload.id || payload.event_id || `evt_${Date.now()}`;
        const existingLog = await database_1.default.webhookLog.findFirst({
            where: { eventId, gateway: gateway.toUpperCase() },
        });
        if (existingLog) {
            logger_1.logger.warn(`Duplicate webhook received: ${eventId} for gateway: ${gateway}`);
            return { status: 'DUPLICATE' };
        }
        // Save initial webhook log
        const log = await database_1.default.webhookLog.create({
            data: {
                gateway: gateway.toUpperCase(),
                eventId,
                eventType: payload.event || payload.type,
                payload: payload,
                processedStatus: 'PENDING',
            },
        });
        try {
            const gatewayClient = await payment_gateway_factory_1.PaymentGatewayFactory.getGateway(gateway);
            const parsedWebhook = await gatewayClient.handleWebhook(payload, signature);
            if (parsedWebhook.status === 'SUCCESS') {
                const payment = await database_1.default.payment.findFirst({
                    where: {
                        OR: [
                            { gatewayOrderId: parsedWebhook.orderId },
                            { gatewayPaymentId: parsedWebhook.paymentId },
                        ],
                    },
                });
                if (payment && payment.status !== 'SUCCESS') {
                    await database_1.default.$transaction([
                        database_1.default.payment.update({
                            where: { id: payment.id },
                            data: {
                                status: 'SUCCESS',
                                gatewayPaymentId: parsedWebhook.paymentId,
                            },
                        }),
                        database_1.default.order.update({
                            where: { id: payment.orderId },
                            data: { status: 'PROCESSING' },
                        }),
                        database_1.default.paymentAudit.create({
                            data: {
                                paymentId: payment.id,
                                action: 'WEBHOOK_VERIFY_SUCCESS',
                                statusFrom: 'PENDING',
                                statusTo: 'SUCCESS',
                                performedBy: 'WEBHOOK',
                                details: `Webhook successfully verified payment ID: ${parsedWebhook.paymentId}`,
                            },
                        }),
                    ]);
                    await this.generateInvoice(payment.id);
                }
            }
            await database_1.default.webhookLog.update({
                where: { id: log.id },
                data: { processedStatus: 'PROCESSED' },
            });
            return { status: 'PROCESSED' };
        }
        catch (err) {
            await database_1.default.webhookLog.update({
                where: { id: log.id },
                data: { processedStatus: 'FAILED', errorMessage: err.message },
            });
            throw err;
        }
    }
}
exports.PaymentService = PaymentService;
//# sourceMappingURL=payment.service.js.map