<?php
/**
 * SNMP Poller — Executa via cron a cada 60s
 * Coleta CPU, RAM, Uptime e tráfego de interfaces via SNMP
 */
require_once __DIR__ . '/../config.php';
require_once __DIR__ . '/../db.php';
require_once __DIR__ . '/../includes/functions.php';
require_once __DIR__ . '/../license.php';
require_once __DIR__ . '/includes/snmp.php';
require_once __DIR__ . '/includes/bandwidth.php';

if (!_mp_env_ready()) { exit(0); }
$_s = license_check(); if ($_s['status'] === 'blocked') { exit(0); } unset($_s);

$pdo = db();

// Busca todos devices ativos com SNMP habilitado
$stmt = $pdo->query("SELECT * FROM nms_devices WHERE active = TRUE AND snmp_enabled = TRUE");
$devices = $stmt->fetchAll(PDO::FETCH_ASSOC);

if (empty($devices)) {
    exit(0);
}

foreach ($devices as $device) {
    $deviceId = (int)$device['id'];
    $now = date('Y-m-d H:i:s');

    // == 1. Coleta métricas do sistema ==
    $cpu    = nms_get_cpu($device);
    $memPct = nms_get_memory_pct($device);
    $uptime = nms_get_uptime($device);
    $status = ($cpu !== null || $uptime !== null) ? 'online' : 'offline';

    // Atualiza status e métricas no device
    $pdo->prepare("
        UPDATE nms_devices
        SET last_status = ?, last_check_at = ?, last_cpu = ?, last_memory_pct = ?, uptime_seconds = ?
        WHERE id = ?
    ")->execute([$status, $now, $cpu, $memPct, $uptime, $deviceId]);

    // Salva histórico de métricas
    if ($status === 'online') {
        $pdo->prepare("
            INSERT INTO nms_device_metrics (device_id, cpu_pct, memory_pct, uptime_seconds, recorded_at)
            VALUES (?, ?, ?, ?, ?)
        ")->execute([$deviceId, $cpu, $memPct, $uptime, $now]);
    }

    if ($status === 'offline') {
        continue;
    }

    // == 2. Coleta interfaces ==
    $interfaces = nms_get_interfaces($device);
    if (empty($interfaces)) {
        continue;
    }

    // Busca valores anteriores (octetos + status de alerta)
    $prevStmt = $pdo->prepare("SELECT id, if_index, last_in_octets, last_out_octets, last_polled_at, last_status, alert_on_down, alert_email, last_alert_sent_at, last_alert_status FROM nms_interfaces WHERE device_id = ?");
    $prevStmt->execute([$deviceId]);
    $prevData = [];
    foreach ($prevStmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
        $prevData[$row['if_index']] = $row;
    }

    $upsertIface = $pdo->prepare("
        INSERT INTO nms_interfaces (device_id, if_index, if_name, if_alias, if_speed_bps, last_status, last_in_bps, last_out_bps, last_in_octets, last_out_octets, last_polled_at)
        VALUES (:device_id, :if_index, :if_name, :if_alias, :if_speed_bps, :last_status, :last_in_bps, :last_out_bps, :last_in_octets, :last_out_octets, :last_polled_at)
        ON CONFLICT (device_id, if_index) DO UPDATE SET
            if_name         = EXCLUDED.if_name,
            if_alias        = EXCLUDED.if_alias,
            if_speed_bps    = EXCLUDED.if_speed_bps,
            last_status     = EXCLUDED.last_status,
            last_in_bps     = EXCLUDED.last_in_bps,
            last_out_bps    = EXCLUDED.last_out_bps,
            last_in_octets  = EXCLUDED.last_in_octets,
            last_out_octets = EXCLUDED.last_out_octets,
            last_polled_at  = EXCLUDED.last_polled_at
    ");

    $insBw = $pdo->prepare("
        INSERT INTO nms_bandwidth_history (interface_id, in_bps, out_bps, recorded_at)
        VALUES (?, ?, ?, ?)
    ");

    foreach ($interfaces as $idx => $iface) {
        $prev      = $prevData[$idx] ?? null;
        $inBps     = null;
        $outBps    = null;

        if ($prev && $prev['last_polled_at']) {
            $deltaSeconds = round((strtotime($now) - strtotime($prev['last_polled_at'])));
            if ($deltaSeconds > 0) {
                $inBps  = calculate_bps($prev['last_in_octets'],  $iface['in_octets'],  $deltaSeconds);
                $outBps = calculate_bps($prev['last_out_octets'], $iface['out_octets'], $deltaSeconds);
            }
        }

        $upsertIface->execute([
            ':device_id'    => $deviceId,
            ':if_index'     => $iface['if_index'],
            ':if_name'      => $iface['if_name'],
            ':if_alias'     => $iface['if_alias'],
            ':if_speed_bps' => $iface['if_speed_bps'],
            ':last_status'  => $iface['status'],
            ':last_in_bps'  => $inBps,
            ':last_out_bps' => $outBps,
            ':last_in_octets'  => $iface['in_octets'],
            ':last_out_octets' => $iface['out_octets'],
            ':last_polled_at'  => $now,
        ]);

        // Busca ID e dados de alerta da interface
        $ifIdStmt = $pdo->prepare("SELECT id FROM nms_interfaces WHERE device_id = ? AND if_index = ?");
        $ifIdStmt->execute([$deviceId, $idx]);
        $ifId = $ifIdStmt->fetchColumn();

        // Registra histórico de banda se tiver dados calculados
        if ($ifId && ($inBps !== null || $outBps !== null)) {
            $insBw->execute([$ifId, $inBps ?? 0, $outBps ?? 0, $now]);
        }

        // Detecta transição de status e envia alerta se configurado
        $prevStatus = $prev['last_status'] ?? null;
        $newStatus  = $iface['status'];
        if ($ifId && $prevStatus !== null && $prevStatus !== $newStatus
            && !empty($prev['alert_on_down']) && !empty($prev['alert_email'])) {
            $lastSent  = $prev['last_alert_sent_at'];
            $cooldownOk = !$lastSent || (time() - strtotime($lastSent)) >= 300;
            $statusChanged = ($prev['last_alert_status'] ?? null) !== $newStatus;
            if ($cooldownOk || $statusChanged) {
                $fakeIp = [
                    'label'   => ($iface['if_alias'] ?: $iface['if_name']) . ' — ' . $device['name'],
                    'host'    => $iface['if_name'],
                    'user_id' => $device['user_id'],
                ];
                $emailStatus = $newStatus === 'down' ? 'offline' : 'online';
                $userTz = get_user_timezone($pdo, (int)$device['user_id']);
                $duration = ($newStatus === 'up' && $prevStatus === 'down' && $lastSent)
                    ? format_outage_duration($lastSent) : null;
                $content = build_alert_email_content($fakeIp, $emailStatus, null, null, $userTz, $duration);
                $err = null;
                send_email_message($prev['alert_email'], $content['subject'], $content['text'], $err, $content['html']);
                $pdo->prepare("UPDATE nms_interfaces SET last_alert_sent_at=?, last_alert_status=? WHERE id=?")
                    ->execute([$now, $newStatus, $ifId]);
                // Registra evento de queda/recuperação
                if ($newStatus === 'down') {
                    $pdo->prepare("INSERT INTO nms_interface_events (interface_id, started_at, alert_sent) VALUES (?, ?, TRUE)")
                        ->execute([$ifId, $now]);
                } elseif ($newStatus === 'up') {
                    $pdo->prepare("
                        UPDATE nms_interface_events
                        SET recovered_at = ?, duration_seconds = EXTRACT(EPOCH FROM (?::timestamptz - started_at))::INT
                        WHERE id = (
                            SELECT id FROM nms_interface_events
                            WHERE interface_id = ? AND recovered_at IS NULL
                            ORDER BY started_at DESC LIMIT 1
                        )
                    ")->execute([$now, $now, $ifId]);
                }
            }
        }
    }
}

echo "[" . date('H:i:s') . "] SNMP Poller concluído. " . count($devices) . " device(s) processado(s).\n";
