/**
 * WhatsApp Webhook Routes
 *
 * Handles webhook verification (GET) and event processing (POST) from the
 * WhatsApp Business Platform. Follows the same pattern as emailWebhooks.ts:
 * public endpoints (no auth middleware), with verification via the webhook
 * verify token and HMAC-SHA256 signature validation on event payloads.
 *
 * Webhook flow:
 * 1. Meta sends GET /webhooks/whatsapp with hub.mode=subscribe & hub.verify_token
 * 2. We verify the token against WhatsAppAppConfig.webhookVerifyToken (timing-safe)
 * 3. Meta sends hub.challenge back as confirmation
 * 4. On each event, Meta sends POST /webhooks/whatsapp with X-Hub-Signature-256
 * 5. We verify the HMAC-SHA256 signature using the App Secret
 * 6. Route the event by phone_number_id to find the tenant's WhatsAppConnection
 * 7. Process message/status events and always return 200
 */

import express, { Request, Response } from 'express';
import crypto from 'crypto';
import { getWhatsAppCredentials } from '../services/whatsapp/whatsappAuth';

const router = express.Router();

// ============================================
// HMAC-SHA256 VERIFICATION
// ============================================

/**
 * Verify the X-Hub-Signature-256 header on webhook POST payloads.
 * Meta signs every POST body with HMAC-SHA256 using the App Secret.
 * This is the same approach used by Facebook/Instagram webhooks.
 */
async function verifyHubSignature(rawBody: string, signature: string): Promise<boolean> {
  if (!signature) return false;

  const credentials = await getWhatsAppCredentials();
  if (!credentials) return false;

  // Signature format: "sha256=<hex>"
  const expectedPrefix = 'sha256=';
  if (!signature.startsWith(expectedPrefix)) return false;

  const expectedSig = crypto
    .createHmac('sha256', credentials.appSecret)
    .update(rawBody)
    .digest('hex');

  const receivedSig = signature.slice(expectedPrefix.length);

  // Timing-safe comparison to prevent timing attacks
  const sigBuf = Buffer.from(receivedSig, 'hex');
  const expBuf = Buffer.from(expectedSig, 'hex');
  if (sigBuf.length !== expBuf.length) return false;
  return crypto.timingSafeEqual(sigBuf, expBuf);
}

/**
 * Constant-time string comparison for the verify token check.
 */
function timingSafeEqualStr(a: string, b: string): boolean {
  const ab = Buffer.from(a);
  const bb = Buffer.from(b);
  if (ab.length !== bb.length) return false;
  return crypto.timingSafeEqual(ab, bb);
}

// ============================================
// GET /whatsapp — Webhook Verification (Meta handshake)
// ============================================

router.get('/whatsapp', async (req: Request, res: Response) => {
  try {
    const mode = req.query['hub.mode'] as string;
    const token = req.query['hub.verify_token'] as string;
    const challenge = req.query['hub.challenge'] as string;

    if (mode !== 'subscribe' || !token || !challenge) {
      console.warn('[WhatsApp Webhook] GET rejected: missing hub.mode, hub.verify_token, or hub.challenge');
      res.status(400).send('Bad Request');
      return;
    }

    const credentials = await getWhatsAppCredentials();
    if (!credentials) {
      console.warn('[WhatsApp Webhook] GET rejected: no WhatsApp credentials configured');
      res.status(403).send('Forbidden');
      return;
    }

    // Timing-safe comparison of the verify token
    if (!timingSafeEqualStr(token, credentials.webhookVerifyToken)) {
      console.warn('[WhatsApp Webhook] GET rejected: verify token mismatch');
      res.status(403).send('Forbidden');
      return;
    }

    console.log('[WhatsApp Webhook] Verification successful');
    res.status(200).send(challenge);
  } catch (error) {
    console.error('[WhatsApp Webhook] Verification error:', error);
    res.status(500).send('Internal Server Error');
  }
});

// ============================================
// POST /whatsapp — Webhook Event Processing
// ============================================

router.post('/whatsapp', async (req: Request, res: Response) => {
  // Always return 200 quickly — Meta retries on non-200
  const rawBody = typeof req.body === 'string' ? req.body : JSON.stringify(req.body);
  const signature = req.headers['x-hub-signature-256'] as string;

  try {
    // 1. Verify HMAC signature (if App Secret is configured)
    const credentials = await getWhatsAppCredentials();
    if (credentials && signature) {
      const isValid = await verifyHubSignature(rawBody, signature);
      if (!isValid) {
        console.warn('[WhatsApp Webhook] POST rejected: invalid HMAC signature');
        // Still return 200 to prevent Meta from retrying
        res.status(200).send('OK');
        return;
      }
    } else if (!credentials) {
      console.warn('[WhatsApp Webhook] No credentials configured, skipping signature verification');
    } else {
      console.warn('[WhatsApp Webhook] No X-Hub-Signature-256 header present');
    }

    const payload = req.body;
    const object = payload?.object;

    // WhatsApp Business API payloads have object === 'whatsapp_business_account'
    if (object !== 'whatsapp_business_account') {
      console.warn('[WhatsApp Webhook] Unknown object type:', object);
      res.status(200).send('OK');
      return;
    }

    const entries: any[] = Array.isArray(payload.entry) ? payload.entry : [];

    for (const entry of entries) {
      const changes: any[] = Array.isArray(entry.changes) ? entry.changes : [];
      for (const change of changes) {
        const value = change.value;
        const phoneNumberId = value?.metadata?.phone_number_id;

        // 2. Route by phone_number_id to find the tenant
        if (phoneNumberId) {
          try {
            const { getModels } = await import('../models');
            const { WhatsAppConnection } = getModels();
            const connection = await WhatsAppConnection.findOne({ phoneNumberId });
            if (connection) {
              console.log(`[WhatsApp Webhook] Routed event for phone ${phoneNumberId} to company ${connection.companyId}`);
            } else {
              console.warn(`[WhatsApp Webhook] No connection found for phone_number_id: ${phoneNumberId}`);
            }
          } catch (err) {
            console.error('[WhatsApp Webhook] Error routing by phone_number_id:', err);
          }
        }

        // 3. Process event types
        const messages: any[] = Array.isArray(value?.messages) ? value.messages : [];
        const statuses: any[] = Array.isArray(value?.statuses) ? value.statuses : [];

        for (const msg of messages) {
          console.log(`[WhatsApp Webhook] Incoming message from ${msg.from}, id: ${msg.id}`);
          // Phase 3: Process incoming messages (store, trigger automations, etc.)
        }

        for (const status of statuses) {
          console.log(`[WhatsApp Webhook] Message status: ${status.status} for id: ${status.id}`);
          // Phase 3: Update message delivery status
        }

        // Handle other event types
        if (value?.event_type) {
          console.log(`[WhatsApp Webhook] Event type: ${value.event_type}`);
        }
      }
    }

    res.status(200).send('OK');
  } catch (error) {
    console.error('[WhatsApp Webhook] Error processing webhook:', error);
    // Still return 200 to prevent Meta from retrying
    res.status(200).send('OK');
  }
});

export default router;