<?php
/**
 * SNMP Helper — OIDs proprietários Ubiquiti AirOS
 * Complementa o mikrotik/includes/snmp.php (funções genéricas reutilizadas)
 */
require_once __DIR__ . '/../../mikrotik/includes/snmp.php';

// ── OIDs Ubiquiti AirOS (namespace 1.3.6.1.4.1.41112) ───────────────────────
define('UBNT_AIRMAX_CCQ',      '1.3.6.1.4.1.41112.1.4.1.1.4');   // CCQ % (walk → index 1)
define('UBNT_AIRMAX_SIGNAL',   '1.3.6.1.4.1.41112.1.4.1.1.6');   // RSSI dBm
define('UBNT_AIRMAX_TXRATE',   '1.3.6.1.4.1.41112.1.4.1.1.12');  // Tx rate Kbps
define('UBNT_AIRMAX_RXRATE',   '1.3.6.1.4.1.41112.1.4.1.1.9');   // Rx rate Kbps
define('UBNT_WL_STA_TABLE',    '1.3.6.1.4.1.41112.1.4.7.1.2');   // Tabela de estações (MAC)
define('UBNT_WL_STA_SIGNAL',   '1.3.6.1.4.1.41112.1.4.7.1.4');   // RSSI por estação
define('UBNT_AIRMAX_STA_COUNT','1.3.6.1.4.1.41112.1.4.5.1.4');   // Total de estações (direto)

// OIDs padrão IEEE 802.11 (fallback)
define('DOT11_STA_COUNT',      '1.2.840.10036.1.1.1.9');

// ifHighSpeed — velocidade da interface em Mbps (padrão RFC 2863)
define('OID_IF_HIGH_SPEED',    '1.3.6.1.2.1.31.1.1.1.15');

/**
 * Monta sessão SNMP v2c para um painel Ubiquiti
 */
function ubnt_session(array $panel): array {
    return [
        'hostname'       => $panel['hostname'],
        'snmp_version'   => '2c',
        'snmp_community' => $panel['snmp_community'] ?? 'public',
        'snmp_port'      => $panel['snmp_port'] ?? 161,
    ];
}

/**
 * Conta clientes Wi-Fi associados ao painel.
 * Tenta 3 métodos em cascata:
 *   1. ubntAirMaxStaCount (direto, AirOS 5/6/8)
 *   2. Walk da tabela ubntWlSta (conta entradas MAC)
 *   3. Walk dot11StationCount (IEEE 802.11 padrão)
 */
function ubnt_get_station_count(array $panel): ?int {
    $dev = ubnt_session($panel);

    // Método 1: OID direto de contagem
    $vals = nms_snmpwalk($dev, UBNT_AIRMAX_STA_COUNT);
    if (!empty($vals)) {
        $total = array_sum(array_map('intval', $vals));
        if ($total >= 0) return $total;
    }

    // Método 2: contar entradas da tabela de estações
    $staTable = nms_snmpwalk($dev, UBNT_WL_STA_TABLE);
    if (!empty($staTable)) {
        return count($staTable);
    }

    // Método 3: dot11StationCount padrão IEEE
    $dot11 = nms_snmpwalk($dev, DOT11_STA_COUNT);
    if (!empty($dot11)) {
        return array_sum(array_map('intval', $dot11));
    }

    return null;
}

/**
 * Retorna a velocidade da interface ethernet principal (eth0) em Mbps.
 * Valor: 10, 100 ou 1000. Retorna null se não responder.
 */
function ubnt_get_iface_speed(array $panel): ?int {
    $dev = ubnt_session($panel);

    $speeds = nms_snmpwalk($dev, OID_IF_HIGH_SPEED);
    if (empty($speeds)) return null;

    // Filtra velocidades válidas (10/100/1000 Mbps)
    foreach ($speeds as $spd) {
        $mbps = (int)$spd;
        if (in_array($mbps, [10, 100, 1000], true)) {
            return $mbps;
        }
    }

    // Fallback: retorna a primeira velocidade > 0
    foreach ($speeds as $spd) {
        $mbps = (int)$spd;
        if ($mbps > 0) return $mbps;
    }

    return null;
}

/**
 * Retorna status operacional da interface principal (up/down).
 */
function ubnt_get_iface_status(array $panel): ?string {
    $dev   = ubnt_session($panel);
    $opers = nms_snmpwalk($dev, OID_IF_OPER);
    if (empty($opers)) return null;

    // Procura a primeira interface que não seja loopback (speed > 0)
    $speeds = nms_snmpwalk($dev, OID_IF_HIGH_SPEED);
    foreach ($opers as $idx => $oper) {
        $spd = (int)($speeds[$idx] ?? 0);
        if ($spd >= 10) {
            return ($oper === '1') ? 'up' : 'down';
        }
    }

    // Fallback: primeira entrada
    $first = reset($opers);
    return ($first === '1') ? 'up' : 'down';
}

/**
 * Retorna CCQ (Client Connection Quality) em % — 0 a 100.
 */
function ubnt_get_ccq(array $panel): ?int {
    $dev  = ubnt_session($panel);
    $vals = nms_snmpwalk($dev, UBNT_AIRMAX_CCQ);
    if (empty($vals)) return null;

    $ccq = (int)reset($vals);
    return ($ccq >= 0 && $ccq <= 100) ? $ccq : null;
}

/**
 * Retorna RSSI médio das estações em dBm (valor negativo, ex: -65).
 */
function ubnt_get_signal(array $panel): ?int {
    $dev = ubnt_session($panel);

    // Tenta sinal médio das estações
    $signals = nms_snmpwalk($dev, UBNT_WL_STA_SIGNAL);
    if (!empty($signals)) {
        $numeric = array_filter(array_map('intval', $signals), fn($v) => $v < 0 && $v > -120);
        if (!empty($numeric)) {
            return (int)round(array_sum($numeric) / count($numeric));
        }
    }

    // Fallback: RSSI do link principal
    $main = nms_snmpwalk($dev, UBNT_AIRMAX_SIGNAL);
    if (!empty($main)) {
        $val = (int)reset($main);
        if ($val < 0 && $val > -120) return $val;
    }

    return null;
}

/**
 * Retorna uptime em segundos (usa OID padrão sysUpTime).
 */
function ubnt_get_uptime(array $panel): ?int {
    return nms_get_uptime(ubnt_session($panel));
}

/**
 * Coleta todos os dados do painel de uma vez.
 * Retorna array com: status, client_count, iface_speed, iface_status, ccq, signal_dbm
 */
function ubnt_poll_panel(array $panel): array {
    $uptime  = ubnt_get_uptime($panel);
    $clients = ubnt_get_station_count($panel);
    $speed   = ubnt_get_iface_speed($panel);
    $ifStat  = ubnt_get_iface_status($panel);
    $ccq     = ubnt_get_ccq($panel);
    $signal  = ubnt_get_signal($panel);

    $online = ($uptime !== null || $clients !== null || $speed !== null);

    return [
        'status'       => $online ? 'online' : 'offline',
        'client_count' => $clients,
        'iface_speed'  => $speed,
        'iface_status' => $ifStat,
        'ccq'          => $ccq,
        'signal_dbm'   => $signal,
    ];
}
