<?php
/**
 * MikroTik API Poller — Executa via cron a cada 60s
 * Coleta dados via REST API do RouterOS: PPPoE, interfaces, recursos
 */
require_once __DIR__ . '/../config.php';
require_once __DIR__ . '/../db.php';
require_once __DIR__ . '/../includes/functions.php';
require_once __DIR__ . '/includes/mikrotik_api.php';
require_once __DIR__ . '/includes/bandwidth.php';

$pdo = db();

$stmt = $pdo->query("SELECT * FROM nms_devices WHERE active = TRUE AND api_enabled = TRUE AND type = 'mikrotik'");
$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');

    $api = new MikrotikApi($device);

    // == 1. Recursos do sistema ==
    $res = $api->getSystemResource();
    if (!$res) {
        $pdo->prepare("UPDATE nms_devices SET last_status='offline', last_check_at=? WHERE id=?")
            ->execute([$now, $deviceId]);
        continue;
    }

    $cpuLoad   = isset($res['cpu-load']) ? (int)$res['cpu-load'] : null;
    $totalMem  = isset($res['total-memory']) ? MikrotikApi::parseMemory($res['total-memory']) : 0;
    $freeMem   = isset($res['free-memory'])  ? MikrotikApi::parseMemory($res['free-memory'])  : 0;
    $memPct    = ($totalMem > 0) ? (int)round((($totalMem - $freeMem) / $totalMem) * 100) : null;
    $uptimeSec = isset($res['uptime']) ? MikrotikApi::uptimeToSeconds($res['uptime']) : null;

    $pdo->prepare("
        UPDATE nms_devices
        SET last_status='online', last_check_at=?, last_cpu=?, last_memory_pct=?, uptime_seconds=?
        WHERE id=?
    ")->execute([$now, $cpuLoad, $memPct, $uptimeSec, $deviceId]);

    // Salva métricas históricas
    $pdo->prepare("
        INSERT INTO nms_device_metrics (device_id, cpu_pct, memory_pct, uptime_seconds, recorded_at)
        VALUES (?, ?, ?, ?, ?)
    ")->execute([$deviceId, $cpuLoad, $memPct, $uptimeSec, $now]);

    // == 2. Interfaces ==
    $ifaces = $api->getInterfaces();
    if (is_array($ifaces)) {
        // Carrega status anterior e config de alerta de todas as interfaces do device
        $prevIfStmt = $pdo->prepare("SELECT id, if_index, last_status, alert_on_down, alert_email, last_alert_sent_at, last_alert_status FROM nms_interfaces WHERE device_id = ?");
        $prevIfStmt->execute([$deviceId]);
        $prevIfData = [];
        foreach ($prevIfStmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
            $prevIfData[$row['if_index']] = $row;
        }

        $upsert = $pdo->prepare("
            INSERT INTO nms_interfaces (device_id, if_index, if_name, if_alias, if_speed_bps, last_status, last_polled_at)
            VALUES (:device_id, :if_index, :if_name, :if_alias, :if_speed_bps, :last_status, :last_polled_at)
            ON CONFLICT (device_id, if_index) DO UPDATE SET
                if_name        = EXCLUDED.if_name,
                if_alias       = EXCLUDED.if_alias,
                last_status    = EXCLUDED.last_status,
                last_polled_at = EXCLUDED.last_polled_at
        ");
        foreach ($ifaces as $i => $iface) {
            $ifIndex   = $i + 1;
            $newStatus = ($iface['running'] ?? false) ? 'up' : 'down';
            $upsert->execute([
                ':device_id'      => $deviceId,
                ':if_index'       => $ifIndex,
                ':if_name'        => $iface['name'] ?? "if{$i}",
                ':if_alias'       => $iface['comment'] ?? null,
                ':if_speed_bps'   => null,
                ':last_status'    => $newStatus,
                ':last_polled_at' => $now,
            ]);

            // Detecta transição e envia alerta se configurado
            $prev = $prevIfData[$ifIndex] ?? null;
            if ($prev && $prev['last_status'] !== $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) {
                    $ifName  = $iface['name'] ?? "if{$i}";
                    $ifAlias = $iface['comment'] ?? null;
                    $fakeIp  = [
                        'label'   => ($ifAlias ?: $ifName) . ' — ' . $device['name'],
                        'host'    => $ifName,
                        'user_id' => $device['user_id'],
                    ];
                    $emailStatus = $newStatus === 'down' ? 'offline' : 'online';
                    $userTz  = get_user_timezone($pdo, (int)$device['user_id']);
                    $duration = ($newStatus === 'up' && $prev['last_status'] === '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 device_id=? AND if_index=?")
                        ->execute([$now, $newStatus, $deviceId, $ifIndex]);
                    // Registra evento de queda/recuperação
                    $ifId = isset($prev['id']) ? (int)$prev['id'] : null;
                    if ($ifId) {
                        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]);
                        }
                    }
                }
            }
        }
    }

    // == 3. Clientes PPPoE ativos ==
    $pppoe = $api->getPppoeActive();
    if (is_array($pppoe)) {
        // Remove snapshot anterior do device
        $pdo->prepare("DELETE FROM nms_pppoe_clients WHERE device_id = ? AND DATE(snapshot_at) = CURRENT_DATE")
            ->execute([$deviceId]);

        $ins = $pdo->prepare("
            INSERT INTO nms_pppoe_clients (device_id, username, caller_id, address, uptime_seconds, interface, service, rx_bytes, tx_bytes, snapshot_at)
            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
        ");

        foreach ($pppoe as $client) {
            $upSec = isset($client['uptime']) ? MikrotikApi::uptimeToSeconds($client['uptime']) : null;
            $ins->execute([
                $deviceId,
                $client['name'] ?? '',
                $client['caller-id'] ?? null,
                $client['address'] ?? null,
                $upSec,
                $client['interface'] ?? null,
                $client['service'] ?? null,
                isset($client['bytes-in'])  ? (int)$client['bytes-in']  : null,
                isset($client['bytes-out']) ? (int)$client['bytes-out'] : null,
                $now,
            ]);
        }
    }
}

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