/**
 * Descomplicar® Crescimento Digital
 * https://descomplicar.pt
 */

<?php

defined('BASEPATH') or exit('No direct script access allowed');

/**
 * Webhook Controller for Moloni Integration
 * 
 * Handles incoming webhooks from Moloni ERP system
 * Processes events and triggers appropriate sync operations
 * 
 * @package     DeskMoloni
 * @author      Descomplicar®
 * @copyright   2025 Descomplicar
 * @version     3.0.0
 */
class WebhookController extends CI_Controller
{
    public function __construct()
    {
        parent::__construct();
        
        // Load required libraries
        $this->load->library('desk_moloni/moloni_api_client');
        $this->load->library('desk_moloni/error_handler');
        
        // Set JSON content type
        $this->output->set_content_type('application/json');
    }
    
    /**
     * Main webhook endpoint for Moloni events
     * 
     * Accepts POST requests from Moloni webhook system
     * URL: admin/desk_moloni/webhook/receive
     */
    public function receive()
    {
        try {
            // Only accept POST requests
            if ($this->input->method() !== 'post') {
                throw new Exception('Only POST requests allowed', 405);
            }
            
            // Get raw POST data
            $raw_input = file_get_contents('php://input');
            
            if (empty($raw_input)) {
                throw new Exception('Empty webhook payload', 400);
            }
            
            // Decode JSON payload
            $payload = json_decode($raw_input, true);
            
            if (json_last_error() !== JSON_ERROR_NONE) {
                throw new Exception('Invalid JSON payload: ' . json_last_error_msg(), 400);
            }
            
            // Get webhook signature for verification
            $signature = $this->input->get_request_header('X-Moloni-Signature') ?? 
                        $this->input->get_request_header('X-Webhook-Signature');
            
            // Log webhook received
            log_activity('Desk-Moloni: Webhook received - Event: ' . ($payload['event'] ?? 'unknown'));
            
            // Rate limiting check for webhooks
            if (!$this->check_webhook_rate_limit()) {
                throw new Exception('Webhook rate limit exceeded', 429);
            }
            
            // Process webhook through API client
            $success = $this->moloni_api_client->process_webhook($payload, $signature);
            
            if ($success) {
                // Return success response
                $this->output
                    ->set_status_header(200)
                    ->set_output(json_encode([
                        'status' => 'success',
                        'message' => 'Webhook processed successfully',
                        'event' => $payload['event'] ?? null,
                        'timestamp' => date('Y-m-d H:i:s')
                    ]));
            } else {
                throw new Exception('Webhook processing failed', 500);
            }
            
        } catch (Exception $e) {
            // Log error
            $this->error_handler->log_error(
                'webhook_processing',
                $e->getMessage(),
                [
                    'payload' => $payload ?? null,
                    'signature' => $signature ?? null,
                    'ip_address' => $this->input->ip_address(),
                    'user_agent' => $this->input->user_agent()
                ],
                'medium'
            );
            
            // Return error response
            $http_code = is_numeric($e->getCode()) ? $e->getCode() : 500;
            
            $this->output
                ->set_status_header($http_code)
                ->set_output(json_encode([
                    'status' => 'error',
                    'message' => $e->getMessage(),
                    'timestamp' => date('Y-m-d H:i:s')
                ]));
        }
    }
    
    /**
     * Webhook configuration endpoint for administrators
     * 
     * Allows admins to configure webhook settings
     * URL: admin/desk_moloni/webhook/configure
     */
    public function configure()
    {
        // Check if user has admin permissions
        if (!has_permission('desk_moloni', '', 'edit')) {
            access_denied('Desk-Moloni Webhook Configuration');
        }
        
        if ($this->input->post()) {
            $this->handle_webhook_configuration();
        }
        
        $data = [];
        
        // Get current webhook settings
        $data['webhook_url'] = site_url('admin/desk_moloni/webhook/receive');
        $data['webhook_secret'] = get_option('desk_moloni_webhook_secret');
        $data['webhook_enabled'] = (bool)get_option('desk_moloni_webhook_enabled', false);
        $data['webhook_events'] = explode(',', get_option('desk_moloni_webhook_events', 'customer.created,customer.updated,product.created,product.updated,invoice.created,invoice.updated'));
        
        // Available webhook events
        $data['available_events'] = [
            'customer.created' => 'Customer Created',
            'customer.updated' => 'Customer Updated',
            'customer.deleted' => 'Customer Deleted',
            'product.created' => 'Product Created',
            'product.updated' => 'Product Updated',
            'product.deleted' => 'Product Deleted',
            'invoice.created' => 'Invoice Created',
            'invoice.updated' => 'Invoice Updated',
            'invoice.paid' => 'Invoice Paid',
            'estimate.created' => 'Estimate Created',
            'estimate.updated' => 'Estimate Updated'
        ];
        
        // Get webhook statistics
        $data['webhook_stats'] = $this->get_webhook_statistics();
        
        // Generate CSRF token
        $data['csrf_token'] = $this->security->get_csrf_hash();
        
        // Load view
        $data['title'] = _l('desk_moloni_webhook_configuration');
        $this->load->view('admin/includes/header', $data);
        $this->load->view('admin/webhook_configuration', $data);
        $this->load->view('admin/includes/footer');
    }
    
    /**
     * Test webhook endpoint
     * 
     * Allows testing webhook functionality
     * URL: admin/desk_moloni/webhook/test
     */
    public function test()
    {
        // Check permissions
        if (!has_permission('desk_moloni', '', 'view')) {
            access_denied('Desk-Moloni Webhook Test');
        }
        
        try {
            // Create test webhook payload
            $test_payload = [
                'event' => 'test.webhook',
                'data' => [
                    'test' => true,
                    'timestamp' => time(),
                    'message' => 'This is a test webhook from Desk-Moloni'
                ],
                'webhook_id' => uniqid('test_'),
                'created_at' => date('Y-m-d H:i:s')
            ];
            
            // Process test webhook
            $success = $this->moloni_api_client->process_webhook($test_payload);
            
            if ($success) {
                set_alert('success', _l('webhook_test_successful'));
            } else {
                set_alert('danger', _l('webhook_test_failed'));
            }
            
        } catch (Exception $e) {
            set_alert('danger', _l('webhook_test_error') . ': ' . $e->getMessage());
        }
        
        redirect(admin_url('desk_moloni/webhook/configure'));
    }
    
    /**
     * Webhook logs endpoint
     * 
     * Displays webhook processing logs
     * URL: admin/desk_moloni/webhook/logs
     */
    public function logs()
    {
        // Check permissions
        if (!has_permission('desk_moloni', '', 'view')) {
            access_denied('Desk-Moloni Webhook Logs');
        }
        
        $data = [];
        
        // Load logs model
        // Use API client logging or fallback if API log model is unavailable
        if (file_exists(APPPATH . 'modules/desk_moloni/models/Desk_moloni_api_log_model.php')) {
            $this->load->model('desk_moloni/desk_moloni_api_log_model');
        }
        
        // Get webhook logs (last 7 days)
        $data['logs'] = isset($this->desk_moloni_api_log_model) ? $this->desk_moloni_api_log_model->get_logs([
            'endpoint_like' => 'webhook%',
            'start_date' => date('Y-m-d', strtotime('-7 days')),
            'end_date' => date('Y-m-d'),
            'limit' => 100,
            'order_by' => 'timestamp DESC'
        ]) : [];
        
        // Get log statistics
        $data['log_stats'] = [
            'total_webhooks' => count($data['logs']),
            'successful' => count(array_filter($data['logs'], function($log) { return empty($log['error']); })),
            'failed' => count(array_filter($data['logs'], function($log) { return !empty($log['error']); })),
            'last_24h' => count(array_filter($data['logs'], function($log) { 
                return strtotime($log['timestamp']) > (time() - 86400); 
            }))
        ];
        
        // Load view
        $data['title'] = _l('desk_moloni_webhook_logs');
        $this->load->view('admin/includes/header', $data);
        $this->load->view('admin/webhook_logs', $data);
        $this->load->view('admin/includes/footer');
    }
    
    /**
     * Health check endpoint for webhooks
     * 
     * URL: admin/desk_moloni/webhook/health
     */
    public function health()
    {
        try {
            $health_data = [
                'status' => 'healthy',
                'webhook_enabled' => (bool)get_option('desk_moloni_webhook_enabled', false),
                'webhook_secret_configured' => !empty(get_option('desk_moloni_webhook_secret')),
                'timestamp' => date('Y-m-d H:i:s'),
                'checks' => []
            ];
            
            // Check webhook configuration
            if (!$health_data['webhook_enabled']) {
                $health_data['status'] = 'warning';
                $health_data['checks'][] = 'Webhooks are disabled';
            }
            
            if (!$health_data['webhook_secret_configured']) {
                $health_data['status'] = 'warning';
                $health_data['checks'][] = 'Webhook secret not configured';
            }
            
            // Check recent webhook activity
            $this->load->model('desk_moloni_api_log_model');
            $recent_webhooks = $this->desk_moloni_api_log_model->get_logs([
                'endpoint_like' => 'webhook%',
                'start_date' => date('Y-m-d', strtotime('-1 hour')),
                'limit' => 10
            ]);
            
            $health_data['recent_activity'] = [
                'webhooks_last_hour' => count($recent_webhooks),
                'last_webhook' => !empty($recent_webhooks) ? $recent_webhooks[0]['timestamp'] : null
            ];
            
            $this->output
                ->set_status_header(200)
                ->set_output(json_encode($health_data));
                
        } catch (Exception $e) {
            $this->output
                ->set_status_header(500)
                ->set_output(json_encode([
                    'status' => 'error',
                    'message' => $e->getMessage(),
                    'timestamp' => date('Y-m-d H:i:s')
                ]));
        }
    }
    
    /**
     * Handle webhook configuration form submission
     */
    private function handle_webhook_configuration()
    {
        try {
            // Validate CSRF token
            if (!$this->security->get_csrf_hash()) {
                throw new Exception('Invalid CSRF token');
            }
            
            // Get form data
            $webhook_enabled = (bool)$this->input->post('webhook_enabled');
            $webhook_secret = $this->input->post('webhook_secret', true);
            $webhook_events = $this->input->post('webhook_events') ?? [];
            
            // Validate webhook secret
            if ($webhook_enabled && empty($webhook_secret)) {
                throw new Exception('Webhook secret is required when webhooks are enabled');
            }
            
            if (!empty($webhook_secret) && strlen($webhook_secret) < 16) {
                throw new Exception('Webhook secret must be at least 16 characters long');
            }
            
            // Save configuration
            update_option('desk_moloni_webhook_enabled', $webhook_enabled);
            update_option('desk_moloni_webhook_secret', $webhook_secret);
            update_option('desk_moloni_webhook_events', implode(',', $webhook_events));
            
            // Log configuration change
            log_activity('Desk-Moloni: Webhook configuration updated by ' . get_staff_full_name());
            
            set_alert('success', _l('webhook_configuration_saved'));
            
        } catch (Exception $e) {
            log_activity('Desk-Moloni: Webhook configuration failed - ' . $e->getMessage());
            set_alert('danger', _l('webhook_configuration_failed') . ': ' . $e->getMessage());
        }
    }
    
    /**
     * Check webhook rate limiting
     * 
     * @return bool True if within rate limits
     */
    private function check_webhook_rate_limit()
    {
        $rate_limit_key = 'webhook_rate_limit_' . $this->input->ip_address();
        $current_count = $this->session->userdata($rate_limit_key) ?? 0;
        $max_webhooks_per_minute = 60; // Configurable
        
        if ($current_count >= $max_webhooks_per_minute) {
            return false;
        }
        
        // Increment counter with 1 minute expiry
        $this->session->set_userdata($rate_limit_key, $current_count + 1);
        
        return true;
    }
    
    /**
     * Get webhook processing statistics
     * 
     * @return array Statistics data
     */
    private function get_webhook_statistics()
    {
        $this->load->model('desk_moloni_api_log_model');
        
        // Get statistics for last 30 days
        $logs = $this->desk_moloni_api_log_model->get_logs([
            'endpoint_like' => 'webhook%',
            'start_date' => date('Y-m-d', strtotime('-30 days')),
            'limit' => 1000
        ]);
        
        $stats = [
            'total_webhooks' => count($logs),
            'successful' => 0,
            'failed' => 0,
            'by_event' => [],
            'by_day' => []
        ];
        
        foreach ($logs as $log) {
            // Count success/failure
            if (empty($log['error'])) {
                $stats['successful']++;
            } else {
                $stats['failed']++;
            }
            
            // Count by event type
            if (isset($log['endpoint'])) {
                $event = str_replace('webhook:', '', $log['endpoint']);
                $stats['by_event'][$event] = ($stats['by_event'][$event] ?? 0) + 1;
            }
            
            // Count by day
            $day = date('Y-m-d', strtotime($log['timestamp']));
            $stats['by_day'][$day] = ($stats['by_day'][$day] ?? 0) + 1;
        }
        
        return $stats;
    }
}