/**
 * Grubtech Order Receive Webhook - TypeScript (Express.js)
 *
 * This example demonstrates how to receive orders from Grubtech
 * via webhook and process them in your system.
 *
 * Prerequisites:
 * - Node.js 18+
 * - Express.js (npm install express)
 * - crypto module (built-in)
 *
 * Replace the following placeholders:
 * - {{WEBHOOK_SECRET}}: Your webhook secret for signature verification
 * - {{ORDER_PROCESSING_LOGIC}}: Your business logic to process the order
 */

import express, { Request, Response } from 'express';
import crypto from 'crypto';

const app = express();
const PORT = 3000;
const WEBHOOK_SECRET = '{{WEBHOOK_SECRET}}';

// Middleware to parse JSON and preserve raw body for signature verification
app.use(
  express.json({
    verify: (req: any, res, buf) => {
      req.rawBody = buf.toString('utf8');
    },
  })
);

interface OrderItem {
  id: string;
  name: string;
  quantity: number;
  price: number;
  modifiers?: Array<{ id: string; name: string; price: number }>;
}

interface Order {
  orderId: string;
  partnerOrderId?: string;
  status: string;
  createdAt: string;
  customer: {
    name: string;
    phone: string;
    email?: string;
  };
  delivery: {
    type: 'delivery' | 'pickup';
    address?: string;
    city?: string;
    instructions?: string;
  };
  items: OrderItem[];
  totals: {
    subtotal: number;
    tax: number;
    deliveryFee: number;
    total: number;
  };
  payment: {
    method: string;
    status: string;
  };
}

interface WebhookResponse {
  accepted: boolean;
  orderId?: string;
  partnerOrderId?: string;
  message?: string;
  estimatedReadyTime?: string;
}

/**
 * Verify webhook signature
 */
function verifySignature(req: any): boolean {
  const signature = req.headers['x-grubtech-signature'];

  if (!signature) {
    console.error('❌ No signature provided');
    return false;
  }

  // Calculate expected signature using HMAC-SHA256
  const expectedSignature = crypto
    .createHmac('sha256', WEBHOOK_SECRET)
    .update(req.rawBody)
    .digest('hex');

  // Constant-time comparison to prevent timing attacks
  const isValid = crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  );

  if (!isValid) {
    console.error('❌ Invalid signature');
  }

  return isValid;
}

/**
 * Process order (replace with your business logic)
 */
async function processOrder(order: Order): Promise<WebhookResponse> {
  try {
    console.log(`📦 Processing order: ${order.orderId}`);
    console.log(`Customer: ${order.customer.name}`);
    console.log(`Items: ${order.items.length}`);
    console.log(`Total: $${order.totals.total}`);

    // {{ORDER_PROCESSING_LOGIC}}
    // Example: Save to database, notify kitchen, etc.

    // Simulate processing time
    await new Promise((resolve) => setTimeout(resolve, 100));

    // Calculate estimated ready time (example: 30 minutes from now)
    const readyTime = new Date(Date.now() + 30 * 60 * 1000).toISOString();

    return {
      accepted: true,
      orderId: order.orderId,
      partnerOrderId: `POS-${Date.now()}`,
      message: 'Order accepted successfully',
      estimatedReadyTime: readyTime,
    };
  } catch (error) {
    console.error('❌ Order processing error:', error);

    return {
      accepted: false,
      orderId: order.orderId,
      message: `Order rejected: ${error}`,
    };
  }
}

/**
 * Webhook endpoint to receive orders from Grubtech
 */
app.post('/webhooks/grubtech/orders', async (req: Request, res: Response) => {
  try {
    // Verify signature
    if (!verifySignature(req)) {
      return res.status(401).json({
        accepted: false,
        message: 'Invalid signature',
      });
    }

    const order: Order = req.body;

    // Validate order data
    if (!order.orderId || !order.items || order.items.length === 0) {
      return res.status(400).json({
        accepted: false,
        message: 'Invalid order data',
      });
    }

    // Process order
    const response = await processOrder(order);

    // Send response
    const statusCode = response.accepted ? 200 : 400;
    return res.status(statusCode).json(response);
  } catch (error) {
    console.error('❌ Webhook error:', error);
    return res.status(500).json({
      accepted: false,
      message: 'Internal server error',
    });
  }
});

/**
 * Health check endpoint
 */
app.get('/health', (req: Request, res: Response) => {
  res.json({ status: 'ok' });
});

// Start server
app.listen(PORT, () => {
  console.log(`✅ Webhook server listening on port ${PORT}`);
  console.log(`Webhook URL: http://localhost:${PORT}/webhooks/grubtech/orders`);
});
