<?php
/**
 * System Statistics API for WHMCS Integration
 * Provides server resource usage and statistics
 */

header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *'); // Configure appropriately for production
header('Access-Control-Allow-Methods: GET, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, X-API-Key, X-API-Secret, Authorization');

// Handle preflight requests
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    exit(0);
}

require_once(__DIR__ . '/../../libs/api_auth.php');

try {
    // Authenticate and check permissions
    $authData = api_authenticate('system_stats');
    
    $method = $_SERVER['REQUEST_METHOD'];
    $action = $_GET['action'] ?? 'stats';
    
    switch ($method) {
        case 'GET':
            handleGetRequest($action, $authData);
            break;
            
        default:
            api_response(false, null, 'Method not allowed', 405);
    }
    
} catch (Exception $e) {
    error_log("System API Error: " . $e->getMessage());
    api_response(false, null, 'Internal server error', 500);
}

function handleGetRequest($action, $authData) {
    switch ($action) {
        case 'stats':
            getSystemStats();
            break;
            
        case 'health':
            getSystemHealth();
            break;
            
        case 'users':
            getUserStats();
            break;
            
        case 'resources':
            getResourceUsage();
            break;
            
        default:
            api_response(false, null, 'Invalid action. Use: stats, health, users, resources', 400);
    }
}

function getSystemStats() {
    $stats = [
        'server_info' => getServerInfo(),
        'load_average' => getLoadAverage(),
        'memory_usage' => getMemoryUsage(),
        'disk_usage' => getDiskUsage(),
        'docker_stats' => getDockerStats(),
        'user_count' => getUserCount(),
        'uptime' => getSystemUptime(),
        'timestamp' => date('c')
    ];
    
    api_response(true, $stats, 'System statistics retrieved successfully');
}

function getSystemHealth() {
    $health = [
        'status' => 'healthy',
        'checks' => [
            'database' => checkDatabaseHealth(),
            'docker' => checkDockerHealth(),
            'disk_space' => checkDiskSpace(),
            'load_average' => checkLoadAverage(),
            'memory' => checkMemoryUsage()
        ],
        'timestamp' => date('c')
    ];
    
    // Overall health status
    $healthy = true;
    foreach ($health['checks'] as $check) {
        if ($check['status'] !== 'ok') {
            $healthy = false;
            break;
        }
    }
    
    $health['status'] = $healthy ? 'healthy' : 'degraded';
    
    api_response(true, $health, 'System health check completed');
}

function getUserStats() {
    try {
        require_once(__DIR__ . '/../../libs/mysqlmgmt.php');
        $MySQLMgmt = new mysqlmgmt();

        // Pull all hosting users with their stored allowances.
        $resp = $MySQLMgmt->getAllSystemUsersWithResources();
        $users = ($resp['status'] === '0') ? ($resp['users'] ?? []) : [];

        $total_users    = 0;
        $total_cpu      = 0.0;  // cores
        $total_memory_mb = 0;   // MB (converted to GB in response)
        $total_disk_mb  = 0;    // MB (converted to GB in response)
        $total_domains  = 0;
        $any_uncapped   = false;

        foreach ($users as $u) {
            $total_users++;
            $total_domains += intval($u['max_domains'] ?? 0);
            $is_uncapped = !empty($u['uncapped_resources']);

            if ($is_uncapped) {
                // Uncapped: stored CPU/mem caps are meaningless; contribute actual usage.
                // Disk cap is still enforced (real OS quota), so it stays as-stored.
                $any_uncapped = true;
                $usage = $MySQLMgmt->getUserResourceUsage($u['username']);
                $total_cpu       += floatval($usage['cpu_used']    ?? 0);
                $total_memory_mb += intval($usage['memory_used'] ?? 0);
                $total_disk_mb   += intval($u['max_disk_space'] ?? 0);
            } else {
                $total_cpu       += floatval($u['max_cpu_allowance']    ?? 0);
                $total_memory_mb += intval($u['max_memory_allowance'] ?? 0);
                $total_disk_mb   += intval($u['max_disk_space']       ?? 0);
            }
        }

        $stats = [
            'user_counts' => [
                'total_users_with_limits' => $total_users,
                'active_containers'       => getActiveContainerCount(),
            ],
            'resource_allocations' => [
                'total_cpu_cores' => round($total_cpu, 2),
                'total_memory_gb' => round($total_memory_mb / 1024, 2),
                'total_disk_gb'   => round($total_disk_mb / 1024, 2),
                'total_domains'   => $total_domains,
            ],
            'any_uncapped_users' => $any_uncapped,
            'note' => $any_uncapped
                ? 'Uncapped users counted by actual CPU/memory usage (their stored caps are not enforced); disk still uses stored cap.'
                : null,
            'timestamp' => date('c'),
        ];

        api_response(true, $stats, 'User statistics retrieved successfully');

    } catch (Exception $e) {
        error_log("Error getting user stats: " . $e->getMessage());
        api_response(false, null, 'Failed to retrieve user statistics', 500);
    }
}

function getResourceUsage() {
    $usage = [
        'cpu' => getCpuUsage(),
        'memory' => getMemoryUsage(),
        'disk' => getDiskUsage(),
        'network' => getNetworkStats(),
        'timestamp' => date('c')
    ];
    
    api_response(true, $usage, 'Resource usage retrieved successfully');
}

function getServerInfo() {
    return [
        'hostname' => gethostname(),
        'os' => php_uname('s'),
        'kernel' => php_uname('r'),
        'architecture' => php_uname('m'),
        'php_version' => PHP_VERSION,
        'server_software' => $_SERVER['SERVER_SOFTWARE'] ?? 'Unknown'
    ];
}

function getLoadAverage() {
    $loadavg = file_get_contents('/proc/loadavg');
    if ($loadavg) {
        $load = explode(' ', trim($loadavg));
        return [
            '1_minute' => floatval($load[0]),
            '5_minutes' => floatval($load[1]),
            '15_minutes' => floatval($load[2]),
            'running_processes' => explode('/', $load[3])[0],
            'total_processes' => explode('/', $load[3])[1]
        ];
    }
    return null;
}

function getMemoryUsage() {
    $meminfo = file_get_contents('/proc/meminfo');
    if ($meminfo) {
        preg_match_all('/^(\w+):\s+(\d+)\s+kB$/m', $meminfo, $matches);
        $memory = array_combine($matches[1], $matches[2]);
        
        $totalMB = round($memory['MemTotal'] / 1024, 2);
        $freeMB = round($memory['MemFree'] / 1024, 2);
        $availableMB = round($memory['MemAvailable'] / 1024, 2);
        $usedMB = $totalMB - $freeMB;
        
        return [
            'total_mb' => $totalMB,
            'used_mb' => $usedMB,
            'free_mb' => $freeMB,
            'available_mb' => $availableMB,
            'usage_percentage' => round(($usedMB / $totalMB) * 100, 2),
            'cached_mb' => round($memory['Cached'] / 1024, 2),
            'buffers_mb' => round($memory['Buffers'] / 1024, 2)
        ];
    }
    return null;
}

function getDiskUsage() {
    $rootUsage = disk_free_space('/');
    $rootTotal = disk_total_space('/');
    
    if ($rootUsage !== false && $rootTotal !== false) {
        $rootUsed = $rootTotal - $rootUsage;
        
        return [
            'root_filesystem' => [
                'total_gb' => round($rootTotal / (1024 * 1024 * 1024), 2),
                'used_gb' => round($rootUsed / (1024 * 1024 * 1024), 2),
                'free_gb' => round($rootUsage / (1024 * 1024 * 1024), 2),
                'usage_percentage' => round(($rootUsed / $rootTotal) * 100, 2)
            ]
        ];
    }
    return null;
}

function getCpuUsage() {
    // Get CPU usage from /proc/stat
    $cpuInfo = file_get_contents('/proc/stat');
    if ($cpuInfo) {
        $lines = explode("\n", $cpuInfo);
        $cpuLine = $lines[0];
        
        if (preg_match('/^cpu\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)/', $cpuLine, $matches)) {
            $user = intval($matches[1]);
            $nice = intval($matches[2]);
            $system = intval($matches[3]);
            $idle = intval($matches[4]);
            
            $total = $user + $nice + $system + $idle;
            $used = $total - $idle;
            
            return [
                'usage_percentage' => round(($used / $total) * 100, 2),
                'user_time' => $user,
                'system_time' => $system,
                'idle_time' => $idle
            ];
        }
    }
    return null;
}

function getDockerStats() {
    try {
        $output = shell_exec('docker ps --format "table {{.Names}}\t{{.Status}}" 2>/dev/null');
        if ($output) {
            $lines = explode("\n", trim($output));
            array_shift($lines); // Remove header
            
            $running = 0;
            $containers = [];
            
            foreach ($lines as $line) {
                if (trim($line)) {
                    $parts = explode("\t", $line);
                    if (count($parts) >= 2) {
                        $name = trim($parts[0]);
                        $status = trim($parts[1]);
                        
                        $containers[] = [
                            'name' => $name,
                            'status' => $status
                        ];
                        
                        if (strpos($status, 'Up') === 0) {
                            $running++;
                        }
                    }
                }
            }
            
            return [
                'total_containers' => count($containers),
                'running_containers' => $running,
                'containers' => $containers
            ];
        }
    } catch (Exception $e) {
        error_log("Error getting Docker stats: " . $e->getMessage());
    }
    
    return ['total_containers' => 0, 'running_containers' => 0, 'containers' => []];
}

function getUserCount() {
    $userDirs = glob('/docker/users/*', GLOB_ONLYDIR);
    return count($userDirs);
}

function getActiveContainerCount() {
    try {
        $output = shell_exec('docker ps -q 2>/dev/null | wc -l');
        return intval(trim($output));
    } catch (Exception $e) {
        return 0;
    }
}

function getSystemUptime() {
    $uptime = file_get_contents('/proc/uptime');
    if ($uptime) {
        $uptimeSeconds = floatval(explode(' ', trim($uptime))[0]);
        
        $days = floor($uptimeSeconds / 86400);
        $hours = floor(($uptimeSeconds % 86400) / 3600);
        $minutes = floor(($uptimeSeconds % 3600) / 60);
        
        return [
            'seconds' => intval($uptimeSeconds),
            'formatted' => sprintf('%d days, %d hours, %d minutes', $days, $hours, $minutes),
            'days' => $days,
            'hours' => $hours,
            'minutes' => $minutes
        ];
    }
    return null;
}

function getNetworkStats() {
    try {
        $netdev = file_get_contents('/proc/net/dev');
        if ($netdev) {
            $lines = explode("\n", $netdev);
            $totalRx = 0;
            $totalTx = 0;
            
            foreach ($lines as $line) {
                if (strpos($line, ':') !== false && !strpos($line, 'lo:')) {
                    $parts = preg_split('/\s+/', trim($line));
                    if (count($parts) >= 10) {
                        $totalRx += intval($parts[1]); // RX bytes
                        $totalTx += intval($parts[9]); // TX bytes
                    }
                }
            }
            
            return [
                'total_rx_bytes' => $totalRx,
                'total_tx_bytes' => $totalTx,
                'total_rx_mb' => round($totalRx / (1024 * 1024), 2),
                'total_tx_mb' => round($totalTx / (1024 * 1024), 2)
            ];
        }
    } catch (Exception $e) {
        error_log("Error getting network stats: " . $e->getMessage());
    }
    
    return null;
}

// Health check functions
function checkDatabaseHealth() {
    try {
        require_once(__DIR__ . '/../../libs/mysqlmgmt.php');
        $MySQLMgmt = new mysqlmgmt();
        $db = $MySQLMgmt->getMySQLConnection();
        $db->exec("USE whp");
        $stmt = $db->query('SELECT 1');
        $result = $stmt->fetch();
        
        return [
            'status' => $result ? 'ok' : 'error',
            'message' => $result ? 'Database connection successful' : 'Database query failed'
        ];
    } catch (Exception $e) {
        return [
            'status' => 'error',
            'message' => 'Database connection failed: ' . $e->getMessage()
        ];
    }
}

function checkDockerHealth() {
    try {
        $output = shell_exec('docker info 2>/dev/null');
        return [
            'status' => $output ? 'ok' : 'error',
            'message' => $output ? 'Docker daemon is running' : 'Docker daemon not accessible'
        ];
    } catch (Exception $e) {
        return [
            'status' => 'error',
            'message' => 'Docker check failed: ' . $e->getMessage()
        ];
    }
}

function checkDiskSpace() {
    $freeSpace = disk_free_space('/');
    $totalSpace = disk_total_space('/');
    
    if ($freeSpace !== false && $totalSpace !== false) {
        $usagePercent = (($totalSpace - $freeSpace) / $totalSpace) * 100;
        
        return [
            'status' => $usagePercent < 90 ? 'ok' : ($usagePercent < 95 ? 'warning' : 'critical'),
            'message' => sprintf('Disk usage: %.1f%%', $usagePercent),
            'usage_percentage' => round($usagePercent, 1)
        ];
    }
    
    return [
        'status' => 'error',
        'message' => 'Cannot determine disk usage'
    ];
}

function checkLoadAverage() {
    $load = getLoadAverage();
    if ($load) {
        $load1min = $load['1_minute'];
        $cpuCores = intval(shell_exec('nproc'));
        $loadPerCore = $load1min / $cpuCores;
        
        return [
            'status' => $loadPerCore < 0.8 ? 'ok' : ($loadPerCore < 1.5 ? 'warning' : 'critical'),
            'message' => sprintf('Load average: %.2f (%.2f per core)', $load1min, $loadPerCore),
            'load_1min' => $load1min,
            'load_per_core' => round($loadPerCore, 2)
        ];
    }
    
    return [
        'status' => 'error',
        'message' => 'Cannot determine load average'
    ];
}

function checkMemoryUsage() {
    $memory = getMemoryUsage();
    if ($memory) {
        $usagePercent = $memory['usage_percentage'];
        
        return [
            'status' => $usagePercent < 80 ? 'ok' : ($usagePercent < 90 ? 'warning' : 'critical'),
            'message' => sprintf('Memory usage: %.1f%%', $usagePercent),
            'usage_percentage' => $usagePercent
        ];
    }
    
    return [
        'status' => 'error',
        'message' => 'Cannot determine memory usage'
    ];
}
?>