<?php
/**
 * Enhanced Router Monitoring Service
 * Runs every 2 minutes to collect comprehensive router data
 * Usage: */2 * * * * cd /var/www/html/newdesign1/system && php -f router_monitor.php
 */

include "../init.php";

$isCli = php_sapi_name() === 'cli';
if (!$isCli) {
    echo "<pre>";
}

echo "Router Monitor Started: " . date('Y-m-d H:i:s') . "\n";

use PEAR2\Net\RouterOS;
use RouterOS\Exceptions\Socket\TimeoutException;
use RouterOS\Exceptions\Socket\ConnectionException;

class RouterMonitor {
    private $config;
    private $db;
    
    public function __construct() {
        global $config;
        $this->config = $config;
    }
    
    /**
     * Monitor all enabled routers
     */
    public function monitorAllRouters() {
        $routers = ORM::for_table('tbl_routers')->where('enabled', '1')->find_many();
        
        echo "Monitoring " . count($routers) . " routers...\n";
        
        foreach ($routers as $router) {
            $this->monitorRouter($router);
        }
        
        echo "Router monitoring completed: " . date('Y-m-d H:i:s') . "\n";
    }
    
    /**
     * Monitor individual router
     */
    private function monitorRouter($router) {
        $routerId = $router['id'];
        $routerName = $router['name'];
        $ipAddress = $router['ip_address'];
        
        echo "Checking router: $routerName ($ipAddress)...\n";
        
        // Check if router is in circuit breaker state
        if ($this->isCircuitBreakerActive($routerId)) {
            echo "  - Circuit breaker active, skipping\n";
            $this->updateRouterStatus($router, 'Offline', 'Circuit breaker active');
            return;
        }
        
        // Perform comprehensive check
        $monitoringData = $this->performRouterCheck($router);
        
        // Update database with results
        $this->updateRouterData($router, $monitoringData);
        
        // Check for alerts
        $this->checkAlerts($router, $monitoringData);
    }
    
    /**
     * Perform comprehensive router check
     */
    private function performRouterCheck($router) {
        $data = [
            'timestamp' => date('Y-m-d H:i:s'),
            'ping_status' => false,
            'api_status' => false,
            'uptime' => null,
            'free_memory' => null,
            'total_memory' => null,
            'cpu_load' => null,
            'temperature' => null,
            'voltage' => null,
            'error' => null
        ];
        
        // Step 1: Ping check
        $data['ping_status'] = $this->pingRouter($router['ip_address']);
        
        if (!$data['ping_status']) {
            $data['error'] = 'Ping failed';
            return $data;
        }
        
        // Step 2: RouterOS API check
        try {
            $client = Mikrotik::getClient($router['ip_address'], $router['username'], $router['password'], 8);
            
            if (!$client) {
                $data['error'] = 'Failed to create RouterOS client';
                return $data;
            }
            
            // Get system resource data
            $resourceRequest = new RouterOS\Request('/system resource print');
            $resourceResponse = $client->sendSync($resourceRequest, 5);
            $resourceData = $resourceResponse->getAllOfType(RouterOS\Response::TYPE_DATA)[0];
            
            // Get system health data
            $healthRequest = new RouterOS\Request('/system health print');
            $healthResponse = $client->sendSync($healthRequest, 5);
            $healthData = $healthResponse->getAllOfType(RouterOS\Response::TYPE_DATA)[0];
            
            // Extract data
            $data['api_status'] = true;
            $data['uptime'] = $resourceData->getProperty('uptime');
            $data['free_memory'] = (int)$resourceData->getProperty('free-memory');
            $data['total_memory'] = (int)$resourceData->getProperty('total-memory');
            $data['cpu_load'] = (int)$resourceData->getProperty('cpu-load');
            $data['temperature'] = $healthData->getProperty('temperature');
            $data['voltage'] = $healthData->getProperty('voltage');
            
            // Clear circuit breaker on successful connection
            $this->clearCircuitBreaker($router['id']);
            
        } catch (TimeoutException $e) {
            $data['error'] = 'API timeout';
            $this->incrementCircuitBreaker($router['id']);
        } catch (ConnectionException $e) {
            $data['error'] = 'API connection failed';
            $this->incrementCircuitBreaker($router['id']);
        } catch (Exception $e) {
            $data['error'] = 'API error: ' . $e->getMessage();
            $this->incrementCircuitBreaker($router['id']);
        }
        
        return $data;
    }
    
    /**
     * Ping router
     */
    private function pingRouter($ipAddress, $timeout = 5, $count = 3) {
        $ipParts = explode(':', $ipAddress);
        $ip = $ipParts[0];
        $escapedIp = escapeshellarg($ip);
        
        exec("ping -c $count -W $timeout $escapedIp 2>&1", $output, $returnVar);
        
        return $returnVar === 0;
    }
    
    /**
     * Update router status in database
     */
    private function updateRouterStatus($router, $status, $error = null) {
        $router->status = $status;
        $router->last_check = date('Y-m-d H:i:s');
        
        if ($error) {
            $router->last_error = $error;
        }
        
        $router->save();
    }
    
    /**
     * Update router data in database
     */
    private function updateRouterData($router, $data) {
        // Update main router table
        $router->status = ($data['api_status'] && $data['ping_status']) ? 'Online' : 'Offline';
        $router->last_check = $data['timestamp'];
        $router->last_error = $data['error'];
        $router->save();
        
        // Store detailed monitoring data
        $this->storeMonitoringData($router['id'], $data);
    }
    
    /**
     * Store detailed monitoring data
     */
    private function storeMonitoringData($routerId, $data) {
        // Create monitoring record
        $monitoring = ORM::for_table('tbl_router_monitoring')->create();
        $monitoring->router_id = $routerId;
        $monitoring->timestamp = $data['timestamp'];
        $monitoring->ping_status = $data['ping_status'] ? 1 : 0;
        $monitoring->api_status = $data['api_status'] ? 1 : 0;
        $monitoring->uptime = $data['uptime'];
        $monitoring->free_memory = $data['free_memory'];
        $monitoring->total_memory = $data['total_memory'];
        $monitoring->cpu_load = $data['cpu_load'];
        $monitoring->temperature = $data['temperature'];
        $monitoring->voltage = $data['voltage'];
        $monitoring->error = $data['error'];
        $monitoring->save();
        
        // Clean up old records (keep last 7 days)
        $cutoffDate = date('Y-m-d H:i:s', strtotime('-7 days'));
        ORM::for_table('tbl_router_monitoring')
            ->where('timestamp', '<', $cutoffDate)
            ->delete_many();
    }
    
    /**
     * Check for alerts
     */
    private function checkAlerts($router, $data) {
        $alerts = [];
        
        // CPU load alert
        if ($data['cpu_load'] && $data['cpu_load'] > 80) {
            $alerts[] = "High CPU load: {$data['cpu_load']}%";
        }
        
        // Memory usage alert
        if ($data['free_memory'] && $data['total_memory']) {
            $memoryUsage = (($data['total_memory'] - $data['free_memory']) / $data['total_memory']) * 100;
            if ($memoryUsage > 90) {
                $alerts[] = "High memory usage: " . round($memoryUsage, 1) . "%";
            }
        }
        
        // Temperature alert
        if ($data['temperature'] && $data['temperature'] > 60) {
            $alerts[] = "High temperature: {$data['temperature']}°C";
        }
        
        // Send alerts if any
        if (!empty($alerts)) {
            $this->sendAlerts($router, $alerts);
        }
    }
    
    /**
     * Send alerts
     */
    private function sendAlerts($router, $alerts) {
        $message = "Router {$router['name']} alerts:\n" . implode("\n", $alerts);
        
        // Send to admin users
        $users = ORM::for_table('tbl_users')->where('user_type', 'Admin')->find_many();
        foreach ($users as $user) {
            $this->sendSMS($user['phone'], $message);
            $this->sendWhatsApp($user['phone'], $message);
        }
    }
    
    /**
     * Circuit breaker methods
     */
    private function isCircuitBreakerActive($routerId) {
        if (!function_exists('apcu_fetch')) return false;
        
        $key = "router_failures_$routerId";
        $timeKey = "router_failures_{$routerId}_time";
        
        $failureCount = apcu_fetch($key) ?: 0;
        $lastFailure = apcu_fetch($timeKey) ?: 0;
        
        return $failureCount >= 3 && (time() - $lastFailure) < 300; // 5 minutes
    }
    
    private function incrementCircuitBreaker($routerId) {
        if (!function_exists('apcu_store')) return;
        
        $key = "router_failures_$routerId";
        $timeKey = "router_failures_{$routerId}_time";
        
        $failureCount = apcu_fetch($key) ?: 0;
        apcu_store($key, $failureCount + 1, 300);
        apcu_store($timeKey, time(), 300);
    }
    
    private function clearCircuitBreaker($routerId) {
        if (!function_exists('apcu_delete')) return;
        
        $key = "router_failures_$routerId";
        $timeKey = "router_failures_{$routerId}_time";
        
        apcu_delete($key);
        apcu_delete($timeKey);
    }
    
    /**
     * Send SMS
     */
    private function sendSMS($phone, $message) {
        // Implementation depends on your SMS provider
        // This is a placeholder
        echo "SMS to $phone: $message\n";
    }
    
    /**
     * Send WhatsApp
     */
    private function sendWhatsApp($phone, $message) {
        // Implementation depends on your WhatsApp provider
        // This is a placeholder
        echo "WhatsApp to $phone: $message\n";
    }
}

// Run the monitor
$monitor = new RouterMonitor();
$monitor->monitorAllRouters();
?>
