#!/usr/bin/env node

/**
 * Webhook Test Script
 * 
 * This script creates a local webhook receiver and tests the webhook system.
 * 
 * Usage:
 *   1. Start your backend server (docker-compose up or npm run dev)
 *   2. Run this script: node test-webhook.js
 *   3. The script will:
 *      - Start a local webhook receiver on port 3001
 *      - Create a webhook in the API
 *      - Send a test webhook
 *      - Wait for incoming webhooks
 */

const express = require('express');
const crypto = require('crypto');
const fetch = require('node-fetch');

// Configuration
const API_URL = process.env.API_URL || 'http://localhost:5000';
const WEBHOOK_PORT = process.env.WEBHOOK_PORT || 3001;
const WEBHOOK_SECRET = 'test_secret_' + Math.random().toString(36).substring(7);

// You need to set this - get it from: curl -X POST http://localhost:5000/api/auth/login -H "Content-Type: application/json" -d '{"key":"YOUR_ADMIN_KEY"}'
const JWT_TOKEN = process.env.JWT_TOKEN || '';

if (!JWT_TOKEN) {
  console.error('\n❌ ERROR: JWT_TOKEN not set!');
  console.error('\nPlease set your JWT token:');
  console.error('  1. Get token: curl -X POST http://localhost:5000/api/auth/login -H "Content-Type: application/json" -d \'{"key":"YOUR_ADMIN_KEY"}\'');
  console.error('  2. Run: JWT_TOKEN="your_token_here" node test-webhook.js');
  console.error('  OR: export JWT_TOKEN="your_token_here" && node test-webhook.js\n');
  process.exit(1);
}

let webhookId = null;
let receivedWebhooks = [];

// Create Express app for webhook receiver
const app = express();

// Important: Parse JSON and keep raw body for signature verification
app.use(express.json({
  verify: (req, res, buf) => {
    req.rawBody = buf.toString('utf8');
  }
}));

// Webhook receiver endpoint
app.post('/webhook/jackbox', (req, res) => {
  console.log('\n📨 Webhook received!');
  console.log('Headers:', {
    'x-webhook-signature': req.headers['x-webhook-signature'],
    'x-webhook-event': req.headers['x-webhook-event'],
    'user-agent': req.headers['user-agent']
  });
  
  const signature = req.headers['x-webhook-signature'];
  
  // Verify signature
  if (!signature || !signature.startsWith('sha256=')) {
    console.log('❌ Missing or invalid signature format');
    return res.status(401).send('Missing or invalid signature');
  }
  
  const expectedSignature = 'sha256=' + crypto
    .createHmac('sha256', WEBHOOK_SECRET)
    .update(req.rawBody)
    .digest('hex');
  
  // Timing-safe comparison
  let isValid = false;
  try {
    isValid = crypto.timingSafeEqual(
      Buffer.from(signature),
      Buffer.from(expectedSignature)
    );
  } catch (err) {
    console.log('❌ Signature verification failed:', err.message);
    return res.status(401).send('Invalid signature');
  }
  
  if (!isValid) {
    console.log('❌ Signature mismatch!');
    console.log('   Expected:', expectedSignature);
    console.log('   Received:', signature);
    return res.status(401).send('Invalid signature');
  }
  
  console.log('✅ Signature verified!');
  console.log('\nPayload:', JSON.stringify(req.body, null, 2));
  
  if (req.body.event === 'game.added') {
    const game = req.body.data.game;
    console.log(`\n🎮 Game Added: ${game.title} from ${game.pack_name}`);
    console.log(`   Players: ${game.min_players}-${game.max_players}`);
    console.log(`   Session ID: ${req.body.data.session.id}`);
    console.log(`   Games Played: ${req.body.data.session.games_played}`);
  }
  
  receivedWebhooks.push(req.body);
  res.status(200).send('OK');
});

// Health check
app.get('/health', (req, res) => {
  res.json({ 
    status: 'ok', 
    webhooksReceived: receivedWebhooks.length 
  });
});

// Start webhook receiver
const server = app.listen(WEBHOOK_PORT, async () => {
  console.log(`\n🚀 Webhook receiver started on http://localhost:${WEBHOOK_PORT}`);
  console.log(`📍 Webhook endpoint: http://localhost:${WEBHOOK_PORT}/webhook/jackbox`);
  console.log(`🔐 Secret: ${WEBHOOK_SECRET}\n`);
  
  // Wait a moment for server to be ready
  await new Promise(resolve => setTimeout(resolve, 500));
  
  // Run tests
  await runTests();
});

async function runTests() {
  console.log('═══════════════════════════════════════════════════════');
  console.log('Starting Webhook Tests');
  console.log('═══════════════════════════════════════════════════════\n');
  
  try {
    // Test 1: Create webhook
    console.log('📝 Test 1: Creating webhook...');
    const createResponse = await fetch(`${API_URL}/api/webhooks`, {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${JWT_TOKEN}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        name: 'Test Webhook',
        url: `http://localhost:${WEBHOOK_PORT}/webhook/jackbox`,
        secret: WEBHOOK_SECRET,
        events: ['game.added']
      })
    });
    
    if (!createResponse.ok) {
      const error = await createResponse.text();
      throw new Error(`Failed to create webhook: ${createResponse.status} ${error}`);
    }
    
    const webhook = await createResponse.json();
    webhookId = webhook.id;
    console.log(`✅ Webhook created with ID: ${webhookId}\n`);
    
    // Test 2: List webhooks
    console.log('📝 Test 2: Listing webhooks...');
    const listResponse = await fetch(`${API_URL}/api/webhooks`, {
      headers: {
        'Authorization': `Bearer ${JWT_TOKEN}`
      }
    });
    
    if (!listResponse.ok) {
      throw new Error(`Failed to list webhooks: ${listResponse.status}`);
    }
    
    const webhooks = await listResponse.json();
    console.log(`✅ Found ${webhooks.length} webhook(s)\n`);
    
    // Test 3: Send test webhook
    console.log('📝 Test 3: Sending test webhook...');
    const testResponse = await fetch(`${API_URL}/api/webhooks/test/${webhookId}`, {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${JWT_TOKEN}`
      }
    });
    
    if (!testResponse.ok) {
      throw new Error(`Failed to send test webhook: ${testResponse.status}`);
    }
    
    console.log('✅ Test webhook sent\n');
    
    // Wait for webhook to be received
    console.log('⏳ Waiting for webhook delivery (5 seconds)...');
    await new Promise(resolve => setTimeout(resolve, 5000));
    
    if (receivedWebhooks.length > 0) {
      console.log(`✅ Received ${receivedWebhooks.length} webhook(s)!\n`);
    } else {
      console.log('⚠️  No webhooks received yet. Check webhook logs.\n');
    }
    
    // Test 4: Check webhook logs
    console.log('📝 Test 4: Checking webhook logs...');
    const logsResponse = await fetch(`${API_URL}/api/webhooks/${webhookId}/logs?limit=10`, {
      headers: {
        'Authorization': `Bearer ${JWT_TOKEN}`
      }
    });
    
    if (!logsResponse.ok) {
      throw new Error(`Failed to get webhook logs: ${logsResponse.status}`);
    }
    
    const logs = await logsResponse.json();
    console.log(`✅ Found ${logs.length} log entries\n`);
    
    if (logs.length > 0) {
      console.log('Recent webhook deliveries:');
      logs.forEach((log, i) => {
        console.log(`  ${i + 1}. Event: ${log.event_type}, Status: ${log.response_status || 'pending'}, Time: ${log.created_at}`);
        if (log.error_message) {
          console.log(`     Error: ${log.error_message}`);
        }
      });
      console.log('');
    }
    
    // Summary
    console.log('═══════════════════════════════════════════════════════');
    console.log('Test Summary');
    console.log('═══════════════════════════════════════════════════════');
    console.log(`✅ Webhook created: ID ${webhookId}`);
    console.log(`✅ Webhooks received: ${receivedWebhooks.length}`);
    console.log(`✅ Webhook logs: ${logs.length} entries`);
    console.log('═══════════════════════════════════════════════════════\n');
    
    console.log('🎉 All tests completed!');
    console.log('\n💡 Next steps:');
    console.log('   1. Add a game to an active session in the Picker page');
    console.log('   2. Watch for the webhook to be received here');
    console.log('   3. Press Ctrl+C to cleanup and exit\n');
    
  } catch (error) {
    console.error('\n❌ Test failed:', error.message);
    console.error('\nMake sure:');
    console.error('  - Backend server is running (http://localhost:5000)');
    console.error('  - JWT_TOKEN is valid');
    console.error('  - Port 3001 is available\n');
    await cleanup();
    process.exit(1);
  }
}

async function cleanup() {
  console.log('\n🧹 Cleaning up...');
  
  if (webhookId) {
    try {
      console.log(`   Deleting webhook ${webhookId}...`);
      const deleteResponse = await fetch(`${API_URL}/api/webhooks/${webhookId}`, {
        method: 'DELETE',
        headers: {
          'Authorization': `Bearer ${JWT_TOKEN}`
        }
      });
      
      if (deleteResponse.ok) {
        console.log('   ✅ Webhook deleted');
      } else {
        console.log('   ⚠️  Could not delete webhook (you may need to delete it manually)');
      }
    } catch (err) {
      console.log('   ⚠️  Error during cleanup:', err.message);
    }
  }
  
  console.log('   Stopping webhook receiver...');
  server.close(() => {
    console.log('   ✅ Server stopped');
    console.log('\n👋 Goodbye!\n');
    process.exit(0);
  });
}

// Handle Ctrl+C
process.on('SIGINT', async () => {
  console.log('\n\n⚠️  Received interrupt signal');
  await cleanup();
});

// Handle errors
process.on('uncaughtException', async (err) => {
  console.error('\n❌ Uncaught exception:', err);
  await cleanup();
});

