// @WHO:   vps-deploy/api/kds/src/routes/webhooks.ts
// @WHAT:  Webhook routes — QRIS payment callbacks and platform integrations
// @PART:  webhooks
// @ENTRY: webhookRouter

import { Router } from 'express';
import crypto from 'crypto';
import { prisma } from '../lib/prisma';
import { getIO } from '../lib/socket';

export const webhookRouter = Router();

const WEBQRIS_WEBHOOK_SECRET = process.env.WEBQRIS_WEBHOOK_SECRET || '';

/**
 * Verify WebQRIS webhook signature using HMAC-SHA256
 * @FLOW:     WEBHOOK_VERIFY
 * @CALLS:    crypto.createHmac
 * @MUTATES:  none
 */
function verifyWebqrisSignature(payload: string, signature: string): boolean {
  if (!WEBQRIS_WEBHOOK_SECRET) {
    console.warn('[WEBHOOK] No WEBQRIS_WEBHOOK_SECRET set — skipping verification');
    return true; // Dev mode: skip verification if no secret
  }

  const expected = crypto
    .createHmac('sha256', WEBQRIS_WEBHOOK_SECRET)
    .update(payload)
    .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(signature, 'hex'),
    Buffer.from(expected, 'hex')
  );
}

// @FLOW:     WEBHOOK_PAID
// @CALLS:    WebQRIS signature verify → DB:payments UPDATE → DB:orders UPDATE
// @MUTATES:  DB:payments (UPDATE status, paidAt), DB:orders (UPDATE status to RECEIVED)
webhookRouter.post('/qris', async (req, res) => {
  try {
    const signature = req.headers['x-webqris-signature'] as string;
    const rawBody = JSON.stringify(req.body);

    // Verify signature
    if (signature && !verifyWebqrisSignature(rawBody, signature)) {
      return res.status(401).json({ error: 'Invalid signature' });
    }

    const { invoice_id, merchant_order_id, status, paid_at } = req.body;

    if (!invoice_id) {
      return res.status(400).json({ error: 'Missing invoice_id' });
    }

    // Find payment by QRIS invoice ID
    const payment = await prisma.payment.findFirst({
      where: { qrInvoiceId: invoice_id },
      include: { order: true },
    });

    if (!payment) {
      console.warn(`[WEBHOOK_QRIS] Payment not found for invoice: ${invoice_id}`);
      return res.status(404).json({ error: 'Payment not found' });
    }

    if (status === 'paid') {
      // Update payment status
      await prisma.payment.update({
        where: { id: payment.id },
        data: {
          status: 'paid',
          paidAt: paid_at ? new Date(paid_at) : new Date(),
        },
      });

      // Update order status
      await prisma.order.update({
        where: { id: payment.orderId },
        data: { status: 'RECEIVED' },
      });

      // Create audit log
      await prisma.auditLog.create({
        data: {
          action: 'PAYMENT_QRIS_PAID',
          entity: 'Payment',
          entityId: payment.id,
          details: `QRIS payment ${invoice_id} confirmed for order ${payment.order.orderNumber}`,
        },
      });

      console.log(`[WEBHOOK_QRIS] Payment confirmed: ${invoice_id} → Order ${payment.order.orderNumber}`);

      // Emit Socket.IO event for payment received
      const io = getIO();
      if (io) {
        const outletId = payment.order.outletId;
        io.to(`outlet:${outletId}:orders`).emit('payment:received', {
          orderId: payment.orderId,
          orderNumber: payment.order.orderNumber,
          paymentId: payment.id,
          method: 'QRIS',
          status: 'paid',
          amount: payment.amount,
        });
        io.to(`outlet:${outletId}:cashier`).emit('payment:received', {
          orderId: payment.orderId,
          orderNumber: payment.order.orderNumber,
          paymentId: payment.id,
          method: 'QRIS',
          status: 'paid',
          amount: payment.amount,
        });
        console.log(`[SOCKET] Emitted payment:received for order ${payment.order.orderNumber}`);
      }
    } else if (status === 'expired') {
      await prisma.payment.update({
        where: { id: payment.id },
        data: { status: 'expired' },
      });

      await prisma.order.update({
        where: { id: payment.orderId },
        data: { status: 'CANCELLED' },
      });

      console.log(`[WEBHOOK_QRIS] Payment expired: ${invoice_id}`);
    }

    res.json({ received: true });
  } catch (err: any) {
    console.error('[WEBHOOK_QRIS]', err);
    res.status(500).json({ error: 'Webhook processing failed', message: err.message });
  }
});

// @FLOW:     WEBHOOK_GOFOOD
// @CALLS:    GoFood signature verify → DB:orders INSERT
// @MUTATES:  DB:orders (INSERT), DB:order_items (INSERT)
webhookRouter.post('/gofood', async (req, res) => {
  try {
    // TODO: Implement GoFood webhook verification and order normalization
    console.log('[WEBHOOK_GOFOOD] Received:', req.body.order_id);
    res.json({ received: true });
  } catch (err: any) {
    console.error('[WEBHOOK_GOFOOD]', err);
    res.status(500).json({ error: 'Webhook processing failed', message: err.message });
  }
});

// @FLOW:     WEBHOOK_GRABFOOD
// @CALLS:    GrabFood signature verify → DB:orders INSERT
// @MUTATES:  DB:orders (INSERT), DB:order_items (INSERT)
webhookRouter.post('/grabfood', async (req, res) => {
  try {
    // TODO: Implement GrabFood webhook verification and order normalization
    console.log('[WEBHOOK_GRABFOOD] Received:', req.body.orderId);
    res.json({ received: true });
  } catch (err: any) {
    console.error('[WEBHOOK_GRABFOOD]', err);
    res.status(500).json({ error: 'Webhook processing failed', message: err.message });
  }
});
