<?php
/**
 * Servicio de Monitoreo de Rate Limiting de Facebook
 * Captura y analiza headers X-App-Usage y X-Business-Use-Case-Usage
 * Fecha: 6 de febrero de 2026
 */

use Predis\Client as RedisClient;

class RateLimitMonitor {
    private $redis;
    private $enabled;
    
    // Umbrales de alerta
    const WARNING_THRESHOLD = 75;  // Advertencia al 75%
    const CRITICAL_THRESHOLD = 90; // Crítico al 90%
    
    public function __construct() {
        try {
            // Usar el mismo patrón que RedisQueue
            $this->redis = new RedisClient([
                'scheme' => getenv('REDIS_SCHEME') ?: 'tcp',
                'host'   => getenv('REDIS_HOST') ?: '127.0.0.1',
                'port'   => getenv('REDIS_PORT') ?: 6379,
                'password' => getenv('REDIS_PASSWORD') ?: null,
                'database' => getenv('REDIS_DB') ?: 0,
            ]);
            
            // Verificar conexión
            $this->redis->ping();
            $this->enabled = true;
        } catch (Exception $e) {
            error_log("RateLimitMonitor: Redis no disponible - " . $e->getMessage());
            $this->enabled = false;
        }
    }
    
    /**
     * Captura y almacena información de rate limit desde headers HTTP
     * @param array $responseHeaders - Headers de la respuesta de Facebook API
     * @param string $endpoint - Endpoint llamado (para tracking)
     */
    public function captureFromHeaders(array $responseHeaders, string $endpoint = 'unknown'): void {
        if (!$this->enabled) return;
        
        try {
            $headerText = is_array($responseHeaders) ? implode("\n", $responseHeaders) : $responseHeaders;
            
            // Buscar X-App-Usage
            if (preg_match('/x-app-usage:\s*({[^}]+})/i', $headerText, $matches)) {
                $usage = json_decode($matches[1], true);
                if ($usage) {
                    $this->recordAppUsage($usage, $endpoint);
                }
            }
            
            // Buscar X-Business-Use-Case-Usage
            if (preg_match('/x-business-use-case-usage:\s*({.+})/i', $headerText, $matches)) {
                $usage = json_decode($matches[1], true);
                if ($usage) {
                    $this->recordBusinessUsage($usage, $endpoint);
                }
            }
            
        } catch (Exception $e) {
            error_log("RateLimitMonitor: Error capturando headers - " . $e->getMessage());
        }
    }
    
    /**
     * Registra uso a nivel de App (X-App-Usage)
     */
    private function recordAppUsage(array $usage, string $endpoint): void {
        $timestamp = time();
        $key = "fb:ratelimit:app:current";
        $historyKey = "fb:ratelimit:app:history";
        
        $data = [
            'call_count' => $usage['call_count'] ?? 0,
            'total_time' => $usage['total_time'] ?? 0,
            'total_cputime' => $usage['total_cputime'] ?? 0,
            'endpoint' => $endpoint,
            'timestamp' => $timestamp,
            'datetime' => date('Y-m-d H:i:s')
        ];
        
        // Guardar estado actual
        $this->redis->setex($key, 3600, json_encode($data));
        
        // Agregar a historial (últimas 100 muestras)
        $this->redis->lpush($historyKey, json_encode($data));
        $this->redis->ltrim($historyKey, 0, 99);
        
        // Verificar umbrales y generar alertas
        $this->checkThresholds('app', $data);
    }
    
    /**
     * Registra uso a nivel de Business (X-Business-Use-Case-Usage)
     */
    private function recordBusinessUsage(array $usage, string $endpoint): void {
        $timestamp = time();
        
        foreach ($usage as $businessId => $metrics) {
            if (!is_array($metrics)) continue;
            
            foreach ($metrics as $metric) {
                if (!is_array($metric)) continue;
                
                $type = $metric['type'] ?? 'unknown';
                $key = "fb:ratelimit:business:{$businessId}:{$type}";
                $historyKey = "fb:ratelimit:business:{$businessId}:{$type}:history";
                
                $data = [
                    'business_id' => $businessId,
                    'type' => $type,
                    'call_count' => $metric['call_count'] ?? 0,
                    'total_time' => $metric['total_time'] ?? 0,
                    'total_cputime' => $metric['total_cputime'] ?? 0,
                    'estimated_time_to_regain_access' => $metric['estimated_time_to_regain_access'] ?? 0,
                    'ads_api_access_tier' => $metric['ads_api_access_tier'] ?? null,
                    'endpoint' => $endpoint,
                    'timestamp' => $timestamp,
                    'datetime' => date('Y-m-d H:i:s')
                ];
                
                // Guardar estado actual
                $this->redis->setex($key, 3600, json_encode($data));
                
                // Agregar a historial
                $this->redis->lpush($historyKey, json_encode($data));
                $this->redis->ltrim($historyKey, 0, 99);
                
                // Verificar umbrales
                $this->checkThresholds('business', $data);
            }
        }
    }
    
    /**
     * Verifica umbrales y genera alertas si es necesario
     */
    private function checkThresholds(string $level, array $data): void {
        $callCount = $data['call_count'] ?? 0;
        $totalTime = $data['total_time'] ?? 0;
        $totalCputime = $data['total_cputime'] ?? 0;
        
        $maxUsage = max($callCount, $totalTime, $totalCputime);
        
        if ($maxUsage >= self::CRITICAL_THRESHOLD) {
            $this->triggerAlert('critical', $level, $data, $maxUsage);
        } elseif ($maxUsage >= self::WARNING_THRESHOLD) {
            $this->triggerAlert('warning', $level, $data, $maxUsage);
        }
    }
    
    /**
     * Dispara una alerta de rate limit
     */
    private function triggerAlert(string $severity, string $level, array $data, float $usage): void {
        $alertKey = "fb:ratelimit:alerts";
        
        $alert = [
            'severity' => $severity,
            'level' => $level,
            'usage' => $usage,
            'data' => $data,
            'timestamp' => time(),
            'datetime' => date('Y-m-d H:i:s')
        ];
        
        // Guardar alerta
        $this->redis->lpush($alertKey, json_encode($alert));
        $this->redis->ltrim($alertKey, 0, 49); // Mantener últimas 50 alertas
        $this->redis->expire($alertKey, 86400 * 7); // 7 días
        
        // Log
        error_log("R
                'error' => 'Redis no disponible',
                'app_usage' => null,
                'business_usage' => [],
                'local_limits' => $this->getLocalLimits(),
                'alerts' => [],
                'status' => 'unavailable'
            rt - {$level} usage at {$usage}% for endpoint: " . ($data['endpoint'] ?? 'unknown'));
    }
    
    /**
     * Obtiene estadísticas actuales de rate limit
     */
    public function getCurrentStats(): array {
        if (!$this->enabled) {
            return ['error' => 'Redis no disponible'];
        }
        
        try {
            $stats = [
                'app_usage' => null,
                'business_usage' => [],
                'local_limits' => $this->getLocalLimits(),
                'alerts' => [],
                'status' => 'healthy'
            ];
            
            // Obtener uso a nivel de app
            $appData = $this->redis->get("fb:ratelimit:app:current");
            if ($appData) {
                $stats['app_usage'] = json_decode($appData, true);
            }
            
            // Obtener uso a nivel de business
            $businessKeys = $this->redis->keys("fb:ratelimit:business:*:current") ?: [];
            foreach ($businessKeys as $key) {
                $data = $this->redis->get($key);
                if ($data) {
                    $decoded = json_decode($data, true);
                    $stats['business_usage'][] = $decoded;
                }
            }
            
            // Obtener alertas recientes
            $alerts = $this->redis->lrange("fb:ratelimit:alerts", 0, 9);
            foreach ($alerts as $alert) {
                $stats['alerts'][] = json_decode($alert, true);
            }
            
            // Determinar estado general
            $maxUsage = 0;
            if ($stats['app_usage']) {
                $maxUsage = max(
                    $stats['app_usage']['call_count'] ?? 0,
                    $stats['app_usage']['total_time'] ?? 0,
                    $stats['app_usage']['total_cputime'] ?? 0
                );
            }
            
            if ($maxUsage >= self::CRITICAL_THRESHOLD) {
                $stats['status'] = 'critical';
            } elseif ($maxUsage >= self::WARNING_THRESHOLD) {
                $stats['status'] = 'warning';
            }
            
            return $stats;
            
        } catch (Exception $e) {
            error_log("RateLimitMonitor: Error obteniendo stats - " . $e->getMessage());
            return ['error' => $e->getMessage()];
        }
    }
    
    /**
     * Obtiene límites locales (del sistema)
     */
    private function getLocalLimits(): array {
        try {
            // Intentar obtener de WhatsAppServiceWithRateLimit si existe
            if (class_exists('WhatsAppServiceWithRateLimit')) {
                $reflection = new ReflectionClass('WhatsAppServiceWithRateLimit');
                
                return [
                    'per_second' => $reflection->getConstant('RATE_LIMIT_PER_SECOND') ?: 80,
                    'per_hour' => $reflection->getConstant('RATE_LIMIT_PER_HOUR') ?: 1000,
                    'per_day' => $reflection->getConstant('RATE_LIMIT_PER_DAY') ?: 10000,
                ];
            }
        } catch (Exception $e) {
            // Fallback a valores por defecto
        }
        
        return [
            'per_second' => 80,
            'per_hour' => 1000,
            'per_day' => 10000,
        ];
    }
    
    /**
     * Obtiene historial de uso
     */
    public function getUsageHistory(string $type = 'app', int $limit = 20): array {
        if (!$this->enabled) {
            return [];
        }
        
        try {
            $key = "fb:ratelimit:{$type}:history";
            $items = $this->redis->lrange($key, 0, $limit - 1);
            
            $history = [];
            foreach ($items as $item) {
                $decoded = json_decode($item, true);
                if ($decoded) {
                    $history[] = $decoded;
                }
            }
            
            return $history;
            
        } catch (Exception $e) {
            error_log("RateLimitMonitor: Error obteniendo historial - " . $e->getMessage());
            return [];
        }
    }
    
    /**
     * Limpia datos antiguos (mantenimiento)
     */
    public function cleanup(): void {
        if (!$this->enabled) return;
        
        try {
            // Limpiar alertas antiguas
            $this->redis->expire("fb:ratelimit:alerts", 86400 * 7);
            
            // Limpiar historiales antiguos
            $historyKeys = $this->redis->keys("fb:ratelimit:*:history") ?: [];
            foreach ($historyKeys as $key) {
                $this->redis->ltrim($key, 0, 99);
            }
            
        } catch (Exception $e) {
            error_log("RateLimitMonitor: Error en cleanup - " . $e->getMessage());
        }
    }
}
