import prisma from '../../../config/database';
import { PaymentGatewayFactory } from './payment-gateway.factory';
import { logger } from '../../../config/logger';

export class PaymentService {
  /**
   * 1. CREATE PAYMENT ORDER
   */
  static async initiatePayment(orderId: string, gateway: string, userId: string, method = 'UPI') {
    const order = await prisma.order.findUnique({
      where: { id: orderId },
      include: { user: true },
    });

    if (!order) {
      throw new Error('Order not found');
    }

    const gatewayClient = await PaymentGatewayFactory.getGateway(gateway);
    const gatewayOrder = await gatewayClient.createOrder(order);

    // DB Upsert payment
    const payment = await prisma.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 prisma.paymentAttempt.create({
      data: {
        paymentId: payment.id,
        gateway: gateway.toUpperCase(),
        amount: order.grandTotal,
        gatewayOrderId: gatewayOrder.gatewayOrderId,
        status: 'PENDING',
      },
    });

    // Create Audit Log
    await prisma.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: string, payload: any) {
    const payment = await prisma.payment.findUnique({
      where: { orderId },
      include: { order: true },
    });

    if (!payment) {
      throw new Error('Payment record not found');
    }

    const gatewayClient = await PaymentGatewayFactory.getGateway(payment.gateway);
    const verification = await gatewayClient.verifyPayment(payload);

    if (verification.success) {
      // Update Payment Status to SUCCESS
      await prisma.$transaction([
        prisma.payment.update({
          where: { id: payment.id },
          data: {
            status: 'SUCCESS',
            gatewayPaymentId: verification.gatewayPaymentId,
            gatewayTransactionId: verification.gatewayTransactionId,
          },
        }),
        prisma.order.update({
          where: { id: orderId },
          data: { status: 'PROCESSING' },
        }),
        prisma.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.info(`Payment verified for order ${orderId}, txn: ${verification.gatewayPaymentId}`);
    } else {
      await prisma.$transaction([
        prisma.payment.update({
          where: { id: payment.id },
          data: { status: 'FAILED' },
        }),
        prisma.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: string, amount: number, reason?: string) {
    const payment = await prisma.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 PaymentGatewayFactory.getGateway(payment.gateway);
    const refundRes = await gatewayClient.refundPayment(payment.gatewayPaymentId || '', amount, reason);

    if (refundRes.success) {
      await prisma.$transaction([
        prisma.payment.update({
          where: { id: payment.id },
          data: { status: 'REFUNDED' },
        }),
        prisma.order.update({
          where: { id: payment.orderId },
          data: { status: 'RETURNED' },
        }),
        prisma.refund.create({
          data: {
            paymentId: payment.id,
            gatewayRefundId: refundRes.gatewayRefundId,
            amount: amount,
            status: 'SUCCESS',
            reason,
            processedAt: new Date(),
          },
        }),
        prisma.paymentAudit.create({
          data: {
            paymentId: payment.id,
            action: 'REFUND_SUCCESS',
            statusFrom: 'SUCCESS',
            statusTo: 'REFUNDED',
            performedBy: 'ADMIN',
            details: `Refund processed successfully. Refund ID: ${refundRes.gatewayRefundId}`,
          },
        }),
      ]);

      logger.info(`Refund succeeded for payment: ${paymentId}, amount: ₹${amount}`);
    }

    return refundRes;
  }

  /**
   * 4. GENERATE INVOICE
   */
  static async generateInvoice(paymentId: string) {
    const payment = await prisma.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 prisma.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: string, payload: any, signature?: string) {
    // Prevent duplicate webhook executions (idempotency check)
    const eventId = payload.id || payload.event_id || `evt_${Date.now()}`;

    const existingLog = await prisma.webhookLog.findFirst({
      where: { eventId, gateway: gateway.toUpperCase() },
    });

    if (existingLog) {
      logger.warn(`Duplicate webhook received: ${eventId} for gateway: ${gateway}`);
      return { status: 'DUPLICATE' };
    }

    // Save initial webhook log
    const log = await prisma.webhookLog.create({
      data: {
        gateway: gateway.toUpperCase(),
        eventId,
        eventType: payload.event || payload.type,
        payload: payload,
        processedStatus: 'PENDING',
      },
    });

    try {
      const gatewayClient = await PaymentGatewayFactory.getGateway(gateway);
      const parsedWebhook = await gatewayClient.handleWebhook(payload, signature);

      if (parsedWebhook.status === 'SUCCESS') {
        const payment = await prisma.payment.findFirst({
          where: {
            OR: [
              { gatewayOrderId: parsedWebhook.orderId },
              { gatewayPaymentId: parsedWebhook.paymentId },
            ],
          },
        });

        if (payment && payment.status !== 'SUCCESS') {
          await prisma.$transaction([
            prisma.payment.update({
              where: { id: payment.id },
              data: {
                status: 'SUCCESS',
                gatewayPaymentId: parsedWebhook.paymentId,
              },
            }),
            prisma.order.update({
              where: { id: payment.orderId },
              data: { status: 'PROCESSING' },
            }),
            prisma.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 prisma.webhookLog.update({
        where: { id: log.id },
        data: { processedStatus: 'PROCESSED' },
      });

      return { status: 'PROCESSED' };
    } catch (err: any) {
      await prisma.webhookLog.update({
        where: { id: log.id },
        data: { processedStatus: 'FAILED', errorMessage: err.message },
      });
      throw err;
    }
  }
}
