<?php
/**
 * Wrapper mejorado de WhatsAppService con Rate Limiting
 * 
 * Agrega control de límites de envío automático usando Redis
 * sin modificar el servicio original
 */

require_once __DIR__ . '/../services/WhatsAppService.php';

use WhatsApp\Queue\RedisQueue;

class WhatsAppServiceWithRateLimit extends WhatsAppService {
    private $queue;
    private $rateLimitEnabled = true;
    
    // Límites de WhatsApp Business API
    const RATE_LIMIT_PER_SECOND = 80;
    const RATE_LIMIT_PER_HOUR = 1000;
    const RATE_LIMIT_PER_DAY = 10000;
    
    public function __construct() {
        parent::__construct();
        
        // Inicializar cola para rate limiting
        $this->queue = new RedisQueue();
        
        // Verificar si rate limiting está habilitado en .env
        $this->rateLimitEnabled = getenv('ENABLE_RATE_LIMIT') !== 'false';
    }
    
    /**
     * Sobrescribir sendMessage con rate limiting
     */
    public function sendTextMessage($to, $message, $meta = null) {
        if (!$this->rateLimitEnabled) {
            return parent::sendTextMessage($to, $message, $meta);
        }
        
        // Verificar límite antes de enviar
        if (!$this->checkRateLimit('messages')) {
            // Si excede límite, encolar para envío posterior
            $this->queueMessage('text', [
                'to' => $to,
                'message' => $message,
                'meta' => $meta
            ]);
            
            return [
                'success' => true,
                'queued' => true,
                'message' => 'Mensaje encolado por rate limit'
            ];
        }
        
        // Registrar envío
        $this->recordSend('messages');
        
        // Enviar normalmente
        return parent::sendTextMessage($to, $message, $meta);
    }
    
    /**
     * Sobrescribir sendTemplateMessage con rate limiting
     */
    public function sendTemplateMessage(
        $to,
        $templateName,
        $language = 'es',
        $bodyParameters = [],
        $headerParameters = [],
        $rawComponents = null,
        $meta = null,
        $dryRun = false
    ) {
        if (!$this->rateLimitEnabled || $dryRun) {
            return parent::sendTemplateMessage(
                $to, $templateName, $language,
                $bodyParameters, $headerParameters,
                $rawComponents, $meta, $dryRun
            );
        }
        
        // Verificar límite
        if (!$this->checkRateLimit('templates')) {
            // Encolar template
            $this->queueMessage('template', [
                'to' => $to,
                'templateName' => $templateName,
                'language' => $language,
                'bodyParameters' => $bodyParameters,
                'headerParameters' => $headerParameters,
                'rawComponents' => $rawComponents,
                'meta' => $meta
            ]);
            
            return [
                'success' => true,
                'queued' => true,
                'message' => 'Template encolada por rate limit'
            ];
        }
        
        // Registrar envío
        $this->recordSend('templates');
        
        // Enviar normalmente
        return parent::sendTemplateMessage(
            $to, $templateName, $language,
            $bodyParameters, $headerParameters,
            $rawComponents, $meta, $dryRun
        );
    }
    
    /**
     * Verificar si se puede enviar según rate limit
     */
    private function checkRateLimit(string $type): bool {
        try {
            $redis = $this->queue->redis ?? new Predis\Client([
                'scheme' => getenv('REDIS_SCHEME') ?: 'tcp',
                'host'   => getenv('REDIS_HOST') ?: '127.0.0.1',
                'port'   => getenv('REDIS_PORT') ?: 6379,
            ]);
            
            $now = time();
            $phoneNumberId = $this->getPhoneNumberId();
            
            // Verificar límite por segundo
            $keySecond = "whatsapp:ratelimit:second:{$phoneNumberId}:{$now}";
            $countSecond = $redis->incr($keySecond);
            if ($countSecond == 1) {
                $redis->expire($keySecond, 1);
            }
            
            if ($countSecond > self::RATE_LIMIT_PER_SECOND) {
                error_log("Rate limit exceeded: second limit ($countSecond/" . self::RATE_LIMIT_PER_SECOND . ")");
                return false;
            }
            
            // Verificar límite por hora
            $hourKey = date('Y-m-d-H');
            $keyHour = "whatsapp:ratelimit:hour:{$phoneNumberId}:{$hourKey}";
            $countHour = $redis->incr($keyHour);
            if ($countHour == 1) {
                $redis->expire($keyHour, 3600);
            }
            
            if ($countHour > self::RATE_LIMIT_PER_HOUR) {
                error_log("Rate limit exceeded: hour limit ($countHour/" . self::RATE_LIMIT_PER_HOUR . ")");
                return false;
            }
            
            // Verificar límite por día
            $dayKey = date('Y-m-d');
            $keyDay = "whatsapp:ratelimit:day:{$phoneNumberId}:{$dayKey}";
            $countDay = $redis->incr($keyDay);
            if ($countDay == 1) {
                $redis->expire($keyDay, 86400);
            }
            
            if ($countDay > self::RATE_LIMIT_PER_DAY) {
                error_log("Rate limit exceeded: day limit ($countDay/" . self::RATE_LIMIT_PER_DAY . ")");
                return false;
            }
            
            return true;
            
        } catch (Exception $e) {
            error_log("Rate limit check failed: " . $e->getMessage());
            // En caso de error, permitir envío para no bloquear
            return true;
        }
    }
    
    /**
     * Registrar envío realizado (incrementar contadores)
     */
    private function recordSend(string $type): void {
        // Los contadores ya se incrementaron en checkRateLimit
        // Esta función existe por si se necesita logging adicional
        
        if (function_exists('writeLog')) {
            writeLog('DEBUG', "Message sent with rate limit check", [
                'type' => $type,
                'timestamp' => date('Y-m-d H:i:s')
            ]);
        }
    }
    
    /**
     * Encolar mensaje que excedió rate limit
     */
    private function queueMessage(string $type, array $data): bool {
        try {
            // Encolar con prioridad normal para envío diferido
            return $this->queue->push('outgoing_messages', [
                'type' => $type,
                'data' => $data,
                'queued_at' => time()
            ], 1);
            
        } catch (Exception $e) {
            error_log("Failed to queue rate-limited message: " . $e->getMessage());
            return false;
        }
    }
    
    /**
     * Obtener estadísticas de rate limit
     */
    public function getRateLimitStats(): array {
        try {
            $redis = new Predis\Client([
                'scheme' => getenv('REDIS_SCHEME') ?: 'tcp',
                'host'   => getenv('REDIS_HOST') ?: '127.0.0.1',
                'port'   => getenv('REDIS_PORT') ?: 6379,
            ]);
            
            $phoneNumberId = $this->getPhoneNumberId();
            $now = time();
            $hourKey = date('Y-m-d-H');
            $dayKey = date('Y-m-d');
            
            $keySecond = "whatsapp:ratelimit:second:{$phoneNumberId}:{$now}";
            $keyHour = "whatsapp:ratelimit:hour:{$phoneNumberId}:{$hourKey}";
            $keyDay = "whatsapp:ratelimit:day:{$phoneNumberId}:{$dayKey}";
            
            return [
                'per_second' => [
                    'current' => (int) $redis->get($keySecond) ?: 0,
                    'limit' => self::RATE_LIMIT_PER_SECOND,
                    'remaining' => max(0, self::RATE_LIMIT_PER_SECOND - ((int) $redis->get($keySecond) ?: 0))
                ],
                'per_hour' => [
                    'current' => (int) $redis->get($keyHour) ?: 0,
                    'limit' => self::RATE_LIMIT_PER_HOUR,
                    'remaining' => max(0, self::RATE_LIMIT_PER_HOUR - ((int) $redis->get($keyHour) ?: 0))
                ],
                'per_day' => [
                    'current' => (int) $redis->get($keyDay) ?: 0,
                    'limit' => self::RATE_LIMIT_PER_DAY,
                    'remaining' => max(0, self::RATE_LIMIT_PER_DAY - ((int) $redis->get($keyDay) ?: 0))
                ]
            ];
            
        } catch (Exception $e) {
            error_log("Failed to get rate limit stats: " . $e->getMessage());
            return [
                'error' => $e->getMessage()
            ];
        }
    }
    
    /**
     * Resetear límites (solo para testing/debugging)
     */
    public function resetRateLimits(): bool {
        try {
            $redis = new Predis\Client([
                'scheme' => getenv('REDIS_SCHEME') ?: 'tcp',
                'host'   => getenv('REDIS_HOST') ?: '127.0.0.1',
                'port'   => getenv('REDIS_PORT') ?: 6379,
            ]);
            
            $phoneNumberId = $this->getPhoneNumberId();
            $pattern = "whatsapp:ratelimit:*:{$phoneNumberId}:*";
            $keys = $redis->keys($pattern);
            
            if (!empty($keys)) {
                $redis->del($keys);
            }
            
            return true;
            
        } catch (Exception $e) {
            error_log("Failed to reset rate limits: " . $e->getMessage());
            return false;
        }
    }
    
    /**
     * Obtener phone_number_id (acceso protegido)
     */
    private function getPhoneNumberId(): string {
        // Usar reflection para acceder a propiedad privada del padre
        $reflection = new ReflectionClass(get_parent_class($this));
        $property = $reflection->getProperty('phoneNumberId');
        $property->setAccessible(true);
        
        return $property->getValue($this) ?: 'default';
    }
    
    /**
     * Habilitar/deshabilitar rate limiting
     */
    public function setRateLimitEnabled(bool $enabled): void {
        $this->rateLimitEnabled = $enabled;
    }
}
