/**
 * Webhook Routes
 * Purpose: Handle payment provider webhook callbacks
 * Routes: Webhooks for Kuda, Opay, Moniepoint, PalmPay, Binance Pay
 */

const express = require('express');
const router = express.Router();
const { getPaymentServiceFactory } = require('../services/payments');

/**
 * Process webhook helper function
 */
async function processWebhook(req, res, provider, pool) {
  try {
    const payload = req.body;
    const payloadString = JSON.stringify(payload);

    // Get signature from headers (different providers use different header names)
    const signature =
      req.headers['x-signature'] ||
      req.headers['signature'] ||
      req.headers['sign'] ||
      req.headers['x-webhook-signature'] ||
      req.headers['x-mono-signature'] ||
      null;

    console.log(`[${provider}] Webhook received:`, {
      headers: req.headers,
      payload: payload
    });

    // Log webhook to database
    const [webhookResult] = await pool.execute(
      `INSERT INTO payment_webhooks (
        provider,
        event_type,
        payload,
        signature,
        is_processed,
        created_at,
        updated_at
      ) VALUES (?, ?, ?, ?, FALSE, NOW(), NOW())`,
      [
        provider,
        payload.event_type || payload.eventType || payload.type || 'payment',
        payloadString,
        signature
      ]
    );

    const webhookId = webhookResult.insertId;

    // Get payment service
    const factory = getPaymentServiceFactory(pool);
    const service = factory.getService(provider);

    // Verify signature if provided
    if (signature) {
      const isValid = service.verifyWebhookSignature(payloadString, signature);

      if (!isValid) {
        console.error(`[${provider}] Invalid webhook signature`);

        await pool.execute(
          `UPDATE payment_webhooks SET
            processing_error = 'Invalid signature',
            retry_count = retry_count + 1,
            updated_at = NOW()
          WHERE id = ?`,
          [webhookId]
        );

        return res.status(401).json({
          success: false,
          message: 'Invalid signature'
        });
      }
    }

    // Handle webhook with service
    const result = await service.handleWebhook(payload, req.headers);

    if (result.success) {
      // Process payment
      await processPaymentFromWebhook(pool, result.data, webhookId);

      // Mark webhook as processed
      await pool.execute(
        `UPDATE payment_webhooks SET
          is_processed = TRUE,
          processed_at = NOW(),
          updated_at = NOW()
        WHERE id = ?`,
        [webhookId]
      );

      console.log(`[${provider}] Webhook processed successfully`);

      return res.status(200).json({
        success: true,
        message: 'Webhook processed'
      });
    } else {
      await pool.execute(
        `UPDATE payment_webhooks SET
          processing_error = 'Webhook handling failed',
          retry_count = retry_count + 1,
          updated_at = NOW()
        WHERE id = ?`,
        [webhookId]
      );

      return res.status(400).json({
        success: false,
        message: 'Webhook handling failed'
      });
    }
  } catch (error) {
    console.error(`[${provider}] Webhook error:`, error);

    return res.status(500).json({
      success: false,
      message: 'Internal server error'
    });
  }
}

/**
 * Process successful payment from webhook
 */
async function processPaymentFromWebhook(pool, data, webhookId) {
  const connection = await pool.getConnection();
  await connection.beginTransaction();

  try {
    // Find deposit by reference
    const [deposits] = await connection.execute(
      `SELECT d.*, pm.name as payment_method_name
       FROM deposits d
       JOIN payment_methods pm ON d.payment_method_id = pm.id
       WHERE d.reference = ? FOR UPDATE`,
      [data.reference]
    );

    if (deposits.length === 0) {
      console.error('Deposit not found for reference:', data.reference);
      await connection.rollback();
      connection.release();
      return;
    }

    const deposit = deposits[0];

    // Check if already completed
    if (deposit.status === 'completed') {
      console.log('Deposit already completed:', deposit.reference);
      await connection.commit();
      connection.release();
      return;
    }

    // Update webhook with deposit ID
    await connection.execute(
      'UPDATE payment_webhooks SET deposit_id = ? WHERE id = ?',
      [deposit.id, webhookId]
    );

    // Get current user balance
    const [users] = await connection.execute(
      'SELECT balance FROM users WHERE id = ?',
      [deposit.user_id]
    );

    const currentBalance = parseFloat(users[0].balance);
    const newBalance = currentBalance + parseFloat(deposit.amount_credited);

    // Update user balance
    await connection.execute(
      'UPDATE users SET balance = ?, updated_at = NOW() WHERE id = ?',
      [newBalance, deposit.user_id]
    );

    // Update deposit
    await connection.execute(
      `UPDATE deposits SET
        transaction_id = ?,
        amount_paid = ?,
        status = 'completed',
        paid_at = NOW(),
        verified_at = NOW(),
        completed_at = NOW(),
        updated_at = NOW()
      WHERE id = ?`,
      [
        data.transaction_id || null,
        data.amount || deposit.amount,
        deposit.id
      ]
    );

    // Create transaction record
    await connection.execute(
      `INSERT INTO transactions (
        user_id,
        deposit_id,
        type,
        amount,
        post_balance,
        status,
        description,
        reference,
        created_at,
        updated_at
      ) VALUES (?, ?, 'credit', ?, ?, 'completed', ?, ?, NOW(), NOW())`,
      [
        deposit.user_id,
        deposit.id,
        deposit.amount_credited,
        newBalance,
        `Deposit via ${deposit.payment_method_name}`,
        deposit.reference
      ]
    );

    await connection.commit();
    connection.release();

    console.log('Payment processed successfully:', deposit.reference);

    // TODO: Send notification to user
    // await sendDepositNotification(deposit.user_id, deposit);
  } catch (error) {
    await connection.rollback();
    connection.release();
    console.error('Process payment error:', error);
    throw error;
  }
}

/**
 * POST /api/webhooks/kuda
 * Handle Kuda Bank webhook
 */
router.post('/kuda', async (req, res) => {
  const pool = req.app.get('pool');
  await processWebhook(req, res, 'kuda', pool);
});

/**
 * POST /api/webhooks/opay
 * Handle Opay webhook
 */
router.post('/opay', async (req, res) => {
  const pool = req.app.get('pool');
  await processWebhook(req, res, 'opay', pool);
});

/**
 * POST /api/webhooks/moniepoint
 * Handle Moniepoint webhook
 */
router.post('/moniepoint', async (req, res) => {
  const pool = req.app.get('pool');
  await processWebhook(req, res, 'moniepoint', pool);
});

/**
 * POST /api/webhooks/palmpay
 * Handle PalmPay webhook
 */
router.post('/palmpay', async (req, res) => {
  const pool = req.app.get('pool');
  await processWebhook(req, res, 'palmpay', pool);
});

/**
 * POST /api/webhooks/binance
 * Handle Binance Pay webhook
 */
router.post('/binance', async (req, res) => {
  const pool = req.app.get('pool');
  await processWebhook(req, res, 'binance', pool);
});

/**
 * POST /api/webhooks/mono
 * Handle Mono webhook (for account verification)
 */
router.post('/mono', async (req, res) => {
  const pool = req.app.get('pool');
  await processWebhook(req, res, 'mono', pool);
});

/**
 * POST /api/webhooks/korapay
 * Handle Korapay webhook
 */
router.post('/korapay', async (req, res) => {
  const pool = req.app.get('pool');
  await processWebhook(req, res, 'korapay', pool);
});

/**
 * POST /api/webhooks/cryptomus
 * Handle Cryptomus webhook
 */
router.post('/cryptomus', async (req, res) => {
  const pool = req.app.get('pool');
  await processWebhook(req, res, 'cryptomus', pool);
});

/**
 * GET /api/webhooks/test
 * Test endpoint to verify webhooks are working
 */
router.get('/test', (req, res) => {
  res.json({
    success: true,
    message: 'Webhook endpoint is working',
    timestamp: new Date().toISOString()
  });
});

module.exports = router;
