<?php
/**
 * Webhook Service for Registration Updates
 * Handles sending registration events to external webhook endpoints
 */

class WebhookService {
    private $pdo;
    private $webhookUrl;
    private $enabledEvents;
    private $retryCount;
    private $timeout;
    
    public function __construct($pdo) {
        $this->pdo = $pdo;
        $this->loadConfiguration();
    }
    
    private function loadConfiguration() {
        $stmt = $this->pdo->prepare("
            SELECT setting_key, setting_value 
            FROM admin_settings 
            WHERE setting_key IN ('webhook_enabled', 'webhook_url', 'webhook_events', 'webhook_retry_count', 'webhook_timeout')
        ");
        $stmt->execute();
        $settings = $stmt->fetchAll(PDO::FETCH_KEY_PAIR);
        
        $this->webhookUrl = $settings['webhook_url'] ?? '';
        $this->enabledEvents = json_decode($settings['webhook_events'] ?? '[]', true);
        $this->retryCount = intval($settings['webhook_retry_count'] ?? 3);
        $this->timeout = intval($settings['webhook_timeout'] ?? 30);
    }
    
    public function isEnabled() {
        $stmt = $this->pdo->prepare("SELECT setting_value FROM admin_settings WHERE setting_key = 'webhook_enabled'");
        $stmt->execute();
        return $stmt->fetchColumn() === 'true';
    }
    
    public function sendWebhook($event, $data, $registrationId = null) {
        if (!$this->isEnabled() || empty($this->webhookUrl)) {
            return false;
        }
        
        if (!in_array($event, $this->enabledEvents)) {
            return false;
        }
        
        $payload = $this->buildPayload($event, $data);
        $headers = $this->buildHeaders($payload);
        
        return $this->sendRequest($payload, $headers);
    }
    
    private function buildPayload($event, $data) {
        return [
            'event' => $event,
            'timestamp' => date('c'),
            'data' => $data,
            'webhook_id' => uniqid('wh_', true)
        ];
    }
    
    private function buildHeaders($payload) {
        return [
            'Content-Type: application/json',
            'User-Agent: XChange-Webhook/1.0'
        ];
    }
    
    private function sendRequest($payload, $headers, $retryAttempt = 0) {
        $ch = curl_init();
        
        curl_setopt_array($ch, [
            CURLOPT_URL => $this->webhookUrl,
            CURLOPT_POST => true,
            CURLOPT_POSTFIELDS => json_encode($payload),
            CURLOPT_HTTPHEADER => $headers,
            CURLOPT_TIMEOUT => $this->timeout,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_SSL_VERIFYPEER => true,
            CURLOPT_FOLLOWLOCATION => false
        ]);
        
        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $error = curl_error($ch);
        curl_close($ch);
        
        // Log webhook attempt
        $this->logWebhookAttempt($payload['event'], $payload['webhook_id'], $httpCode, $response, $error);
        
        if ($httpCode >= 200 && $httpCode < 300) {
            return true;
        }
        
        // Retry logic
        if ($retryAttempt < $this->retryCount && $httpCode >= 500) {
            sleep(pow(2, $retryAttempt)); // Exponential backoff
            return $this->sendRequest($payload, $headers, $retryAttempt + 1);
        }
        
        return false;
    }
    
    private function logWebhookAttempt($event, $webhookId, $httpCode, $response, $error) {
        try {
            $stmt = $this->pdo->prepare("
                INSERT INTO webhook_logs (event, webhook_id, http_code, response, error_message, created_at)
                VALUES (?, ?, ?, ?, ?, NOW())
            ");
            $stmt->execute([$event, $webhookId, $httpCode, $response, $error]);
        } catch (Exception $e) {
            error_log('Failed to log webhook attempt: ' . $e->getMessage());
        }
    }
    
    public function getWebhookLogs($limit = 100, $offset = 0) {
        try {
            $stmt = $this->pdo->prepare("
                SELECT * FROM webhook_logs 
                ORDER BY created_at DESC 
                LIMIT ? OFFSET ?
            ");
            $stmt->execute([$limit, $offset]);
            return $stmt->fetchAll(PDO::FETCH_ASSOC);
        } catch (Exception $e) {
            error_log('Failed to get webhook logs: ' . $e->getMessage());
            return [];
        }
    }
    
    public function getWebhookStats() {
        try {
            $stmt = $this->pdo->prepare("
                SELECT 
                    COUNT(*) as total_webhooks,
                    COUNT(CASE WHEN http_code >= 200 AND http_code < 300 THEN 1 END) as successful,
                    COUNT(CASE WHEN http_code >= 400 THEN 1 END) as failed,
                    COUNT(CASE WHEN http_code >= 500 THEN 1 END) as server_errors
                FROM webhook_logs
            ");
            $stmt->execute();
            return $stmt->fetch(PDO::FETCH_ASSOC);
        } catch (Exception $e) {
            error_log('Failed to get webhook stats: ' . $e->getMessage());
            return [];
        }
    }
    
    public function testWebhook() {
        if (!$this->isEnabled() || empty($this->webhookUrl)) {
            return ['success' => false, 'message' => 'Webhooks are not enabled or configured'];
        }
        
        $testData = [
            'test' => true,
            'message' => 'This is a test webhook from XChange system',
            'timestamp' => date('c')
        ];
        
        $payload = $this->buildPayload('test', $testData);
        $headers = $this->buildHeaders($payload);
        
        $result = $this->sendRequest($payload, $headers);
        
        return [
            'success' => $result,
            'message' => $result ? 'Test webhook sent successfully' : 'Test webhook failed',
            'webhook_id' => $payload['webhook_id']
        ];
    }
    
    /**
     * Get comprehensive registration details for webhook payload
     */
    public function getFullRegistrationData($registrationId) {
        try {
            // Get main registration data
            $stmt = $this->pdo->prepare("
                SELECT r.*, 
                       COUNT(d.id) as delegate_count_actual,
                       GROUP_CONCAT(DISTINCT d.full_name ORDER BY d.delegate_number SEPARATOR ', ') as delegate_names
                FROM registrations r
                LEFT JOIN delegates d ON r.id = d.registration_id
                WHERE r.id = ? OR r.registration_number = ?
                GROUP BY r.id
            ");
            $stmt->execute([$registrationId, $registrationId]);
            $registration = $stmt->fetch(PDO::FETCH_ASSOC);
            
            if (!$registration) {
                return null;
            }
            
            // Get all delegates with full details
            $stmt = $this->pdo->prepare("
                SELECT delegate_number, full_name, badge_name, designation, 
                       dietary_requirements, special_assistance, created_at
                FROM delegates 
                WHERE registration_id = ? 
                ORDER BY delegate_number
            ");
            $stmt->execute([$registration['id']]);
            $delegates = $stmt->fetchAll(PDO::FETCH_ASSOC);
            
            // Get all products/purchases for this registration
            $stmt = $this->pdo->prepare("
                SELECT rp.*, p.name as product_name, p.product_code, p.description as product_description,
                       p.category_id, pc.name as category_name, rp.unit_price, rp.quantity, 
                       (rp.unit_price * rp.quantity) as line_total
                FROM registration_products rp
                JOIN products p ON rp.product_id = p.id
                LEFT JOIN product_categories pc ON p.category_id = pc.id
                WHERE rp.registration_id = ?
                ORDER BY pc.name, p.name
            ");
            $stmt->execute([$registration['id']]);
            $products = $stmt->fetchAll(PDO::FETCH_ASSOC);
            
            // Get payment transactions
            $stmt = $this->pdo->prepare("
                SELECT transaction_type, transaction_status, amount, currency, 
                       transaction_reference, gateway_transaction_id, created_at
                FROM payment_transactions 
                WHERE registration_id = ? 
                ORDER BY created_at DESC
                LIMIT 5
            ");
            $stmt->execute([$registration['id']]);
            $transactions = $stmt->fetchAll(PDO::FETCH_ASSOC);
            
            // Format the comprehensive data
            $fullData = [
                'registration' => [
                    'id' => $registration['id'],
                    'registration_number' => $registration['registration_number'],
                    'created_at' => $registration['created_at'],
                    'updated_at' => $registration['updated_at'],
                    'payment_status' => $registration['payment_status'],
                    'payment_method' => $registration['payment_method'],
                    'total_amount' => (float)$registration['total_amount'],
                    'payment_deadline' => $registration['payment_deadline'],
                    'delegate_count' => $registration['delegate_count'],
                    'delegate_count_actual' => $registration['delegate_count_actual']
                ],
                'contact' => [
                    'salutation' => $registration['contact_salutation'],
                    'full_name' => $registration['contact_full_name'],
                    'badge_name' => $registration['contact_badge_name'],
                    'designation' => $registration['contact_designation'],
                    'department' => $registration['contact_department'],
                    'email' => $registration['contact_email'],
                    'mobile' => $registration['contact_mobile'],
                    'university' => $registration['university_name'],
                    'country' => $registration['country']
                ],
                'delegates' => $delegates,
                'products' => $products,
                'transactions' => $transactions,
                'summary' => [
                    'total_delegates' => count($delegates),
                    'total_products' => count($products),
                    'total_amount' => (float)$registration['total_amount'],
                    'delegate_names' => $registration['delegate_names']
                ]
            ];
            
            return $fullData;
            
        } catch (Exception $e) {
            error_log('Failed to get full registration data: ' . $e->getMessage());
            return null;
        }
    }
}
?>
