<?php

declare(strict_types=1);

namespace ServerManager\Services;

use ServerManager\Core\Database;
use ServerManager\Core\Logger;
use ServerManager\Core\App;
use ServerManager\Services\SSHService;

class MonitoringService
{
    private Database $db;
    private Logger $logger;

    public function __construct()
    {
        $this->db = Database::getInstance();
        $this->logger = Logger::getInstance();
    }

    public function collectMetrics(int $serverId): ?array
    {
        $server = $this->db->fetch('SELECT * FROM servers WHERE id = ? AND status = \'active\'', [$serverId]);

        if (!$server || !$server['is_active']) {
            return null;
        }

        $server = App::getEncryption()->decryptArray($server, ['ssh_password', 'ssh_key']);

        try {
            $ssh = new SSHService();

            if (!$ssh->connect($server, true)) {
                return ['status' => 'offline'];
            }

            $metrics = [
                'server_id' => $serverId,
                'status' => 'online',
                'cpu_usage' => $this->getCPUUsage($ssh),
                'ram_usage' => $this->getRAMUsage($ssh),
                'disk_usage' => $this->getDiskUsage($ssh),
                'load_average' => $this->getLoadAverage($ssh),
                'uptime' => $this->getUptime($ssh),
            ];

            $this->saveMetrics($metrics);

            $ssh->disconnect();

            return $metrics;
        } catch (\Throwable $e) {
            $this->logger->warning("Failed to collect metrics for server {$serverId}: " . $e->getMessage());

            $this->saveMetrics([
                'server_id' => $serverId,
                'status' => 'offline',
                'cpu_usage' => 0,
                'ram_usage' => 0,
                'disk_usage' => 0,
                'load_average' => 0,
                'uptime' => '',
            ]);

            return ['status' => 'offline'];
        }
    }

    public function collectAllMetrics(): array
    {
        $servers = $this->db->fetchAll('SELECT * FROM servers WHERE status = \'active\' AND is_active = 1');
        $results = [];

        foreach ($servers as $server) {
            $results[$server['id']] = $this->collectMetrics($server['id']);
        }

        return $results;
    }

    private function getCPUUsage(SSHService $ssh): float
    {
        $result = $ssh->exec("top -bn1 | grep 'Cpu(s)' | awk '{print $2}' | cut -d'%' -f1");
        return (float) trim($result['output']);
    }

    private function getRAMUsage(SSHService $ssh): float
    {
        $result = $ssh->exec("free | grep Mem | awk '{printf \"%.2f\", $3/$2 * 100}'");
        return (float) trim($result['output']);
    }

    private function getDiskUsage(SSHService $ssh): float
    {
        $result = $ssh->exec("df / | tail -1 | awk '{print $5}' | sed 's/%//'");
        return (float) trim($result['output']);
    }

    private function getLoadAverage(SSHService $ssh): float
    {
        $result = $ssh->exec("cat /proc/loadavg | awk '{print $1}'");
        return (float) trim($result['output']);
    }

    private function getUptime(SSHService $ssh): string
    {
        $result = $ssh->exec("uptime -p");
        return trim(str_replace('up ', '', $result['output']));
    }

    public function saveMetrics(array $metrics): void
    {
        $now = date('Y-m-d H:i:s');

        $this->db->insert('monitoring_history', [
            'server_id' => $metrics['server_id'],
            'status' => $metrics['status'],
            'cpu_usage' => $metrics['cpu_usage'],
            'ram_usage' => $metrics['ram_usage'],
            'disk_usage' => $metrics['disk_usage'],
            'load_average' => $metrics['load_average'],
            'uptime' => $metrics['uptime'] ?? '',
            'created_at' => $now,
        ]);

        $this->db->query(
            "UPDATE servers SET 
                last_check_at = ?,
                current_status = ?,
                cpu_usage = ?,
                ram_usage = ?,
                disk_usage = ?,
                load_average = ?,
                uptime = ?
            WHERE id = ?",
            [
                $now,
                $metrics['status'],
                $metrics['cpu_usage'],
                $metrics['ram_usage'],
                $metrics['disk_usage'],
                $metrics['load_average'],
                $metrics['uptime'] ?? '',
                $metrics['server_id'],
            ]
        );

        $retention = App::getConfig()['monitoring']['retention_days'] ?? 30;
        $this->db->query(
            "DELETE FROM monitoring_history WHERE created_at < DATE_SUB(NOW(), INTERVAL ? DAY)",
            [$retention]
        );
    }

    public function getLatestMetrics(int $serverId): ?array
    {
        return $this->db->fetch(
            'SELECT * FROM monitoring_history WHERE server_id = ? ORDER BY created_at DESC LIMIT 1',
            [$serverId]
        );
    }

    public function getHistoricalMetrics(int $serverId, int $hours = 24): array
    {
        return $this->db->fetchAll(
            'SELECT * FROM monitoring_history 
             WHERE server_id = ? AND created_at >= DATE_SUB(NOW(), INTERVAL ? HOUR) 
             ORDER BY created_at ASC',
            [$serverId, $hours]
        );
    }

    public function getDashboardStats(?array $serverIds = null): array
    {
        $where = '';
        $params = [];

        if ($serverIds !== null) {
            if (empty($serverIds)) {
                $serverIds = [-1];
            }
            $placeholders = implode(',', array_fill(0, count($serverIds), '?'));
            $where = " AND s.id IN ({$placeholders})";
            $params = $serverIds;
        }

        $totalServers = $this->db->fetch("SELECT COUNT(*) as total FROM servers s WHERE s.status = 'active'{$where}", $params);
        $onlineServers = $this->db->fetch(
            "SELECT COUNT(*) as total FROM servers s WHERE s.current_status = 'online' AND s.status = 'active' AND s.is_active = 1{$where}",
            $params
        );
        $offlineServers = $this->db->fetch(
            "SELECT COUNT(*) as total FROM servers s WHERE s.current_status = 'offline' AND s.status = 'active' AND s.is_active = 1{$where}",
            $params
        );

        $avgCpu = $this->db->fetch(
            "SELECT AVG(s.cpu_usage) as avg FROM servers s WHERE s.status = 'active' AND s.is_active = 1 AND s.current_status = 'online'{$where}",
            $params
        );
        $avgRam = $this->db->fetch(
            "SELECT AVG(s.ram_usage) as avg FROM servers s WHERE s.status = 'active' AND s.is_active = 1 AND s.current_status = 'online'{$where}",
            $params
        );
        $avgDisk = $this->db->fetch(
            "SELECT AVG(s.disk_usage) as avg FROM servers s WHERE s.status = 'active' AND s.is_active = 1 AND s.current_status = 'online'{$where}",
            $params
        );

        return [
            'total_servers' => (int) ($totalServers['total'] ?? 0),
            'online_servers' => (int) ($onlineServers['total'] ?? 0),
            'offline_servers' => (int) ($offlineServers['total'] ?? 0),
            'avg_cpu' => round((float) ($avgCpu['avg'] ?? 0), 1),
            'avg_ram' => round((float) ($avgRam['avg'] ?? 0), 1),
            'avg_disk' => round((float) ($avgDisk['avg'] ?? 0), 1),
        ];
    }
}
