<?php
/**
 * API: WLAN-Verwaltung über nmcli (NetworkManager).
 *
 * action=status      GET   Aktueller WLAN-Status (verbundenes Netz, IP, Signal).
 * action=scan        GET   Verfügbare WLAN-Netzwerke scannen.
 * action=connect     POST  Mit einem Netzwerk verbinden (ssid, password).
 * action=forget      POST  Gespeicherte Verbindung löschen (ssid).
 * action=disconnect  POST  WLAN trennen.
 *
 * Voraussetzung: sudo-Rechte für www-data auf nmcli
 *   → wecker/skripts/setup_sudoers_wlan.sh ausführen
 */
require __DIR__ . '/../config.php';
require FUNCTIONS_ROOT . '/functions_common.php';

header('Content-Type: application/json; charset=utf-8');

$action = $_REQUEST['action'] ?? '';

/** nmcli-Binär ermitteln */
function nmcli_bin(): string {
    static $bin = null;
    if ($bin !== null) return $bin;
    foreach (['/usr/bin/nmcli', '/bin/nmcli', '/sbin/nmcli'] as $p) {
        if (file_exists($p)) { $bin = $p; return $bin; }
    }
    $bin = 'nmcli';
    return $bin;
}

/** nmcli ausführen und Ausgabe zurückgeben */
function nmcli(array $args): array {
    $cmd = 'sudo ' . escapeshellarg(nmcli_bin());
    foreach ($args as $a) {
        $cmd .= ' ' . escapeshellarg($a);
    }
    $output = [];
    $exitCode = 0;
    exec($cmd . ' 2>&1', $output, $exitCode);
    return ['exit' => $exitCode, 'lines' => $output, 'raw' => implode("\n", $output)];
}

/** Signalstärke-Icon (0–100 → Balken) */
function signal_bars(int $signal): string {
    if ($signal >= 75) return '▂▄▆█';
    if ($signal >= 50) return '▂▄▆_';
    if ($signal >= 25) return '▂▄__';
    return '▂___';
}

/** WLAN-Interface ermitteln (erstes wlan* Device) */
function wlan_device(): string {
    $r = nmcli(['-t', '-f', 'DEVICE,TYPE', 'device', 'status']);
    foreach ($r['lines'] as $line) {
        $parts = explode(':', $line, 2);
        if (count($parts) === 2 && trim($parts[1]) === 'wifi') {
            return trim($parts[0]);
        }
    }
    return 'wlan0';
}

switch ($action) {

    // ── Status ───────────────────────────────────────────────────────────────
    case 'status': {
        $dev = wlan_device();

        // IN-USE-Flag aus device wifi list ist zuverlässiger als connection show
        $connected = false;
        $ssid      = '';
        $signal    = 0;
        $wifi = nmcli(['-t', '-f', 'IN-USE,SSID,SIGNAL', 'device', 'wifi', 'list', 'ifname', $dev]);
        foreach ($wifi['lines'] as $line) {
            $p = preg_split('/(?<!\\\\):/', $line, 3);
            if (count($p) >= 2 && trim($p[0]) === '*') {
                $connected = true;
                $ssid      = str_replace('\\:', ':', trim($p[1]));
                $signal    = isset($p[2]) ? (int)trim($p[2]) : 0;
                break;
            }
        }

        // IP-Adresse über device show (ohne -t, damit Feldnamen stabil sind)
        $ip = '';
        $show = nmcli(['device', 'show', $dev]);
        foreach ($show['lines'] as $line) {
            // Format: "IP4.ADDRESS[1]:                         192.168.x.x/24"
            if (preg_match('/^IP4\.ADDRESS\[1\]\s*:\s*(.+)$/', $line, $m)) {
                $ip = explode('/', trim($m[1]))[0];
                break;
            }
        }

        echo json_encode([
            'ok'        => true,
            'connected' => $connected,
            'ssid'      => $ssid ?: null,
            'ip'        => $ip   ?: null,
            'signal'    => $signal,
            'device'    => $dev,
        ]);
        break;
    }

    // ── Scan ─────────────────────────────────────────────────────────────────
    case 'scan': {
        $dev = wlan_device();
        // Rescan anstoßen (kann einige Sekunden dauern; Fehler ignorieren)
        nmcli(['device', 'wifi', 'rescan', 'ifname', $dev]);

        $r = nmcli(['-t', '-f', 'IN-USE,SSID,SIGNAL,SECURITY', 'device', 'wifi', 'list', 'ifname', $dev]);
        $nets = [];
        $seen = [];
        foreach ($r['lines'] as $line) {
            if (trim($line) === '') continue;
            // nmcli -t escapes colons with \: – simple split on unescaped :
            $p = preg_split('/(?<!\\\\):/', $line, 4);
            if (count($p) < 4) continue;
            $inUse    = trim($p[0]) === '*';
            $ssid     = str_replace('\\:', ':', trim($p[1]));
            $signal   = (int)trim($p[2]);
            $security = trim($p[3]);

            if ($ssid === '' || $ssid === '--') continue;
            if (isset($seen[$ssid])) {
                // Nur stärkstes Signal behalten
                if ($signal > $seen[$ssid]) {
                    foreach ($nets as &$n) {
                        if ($n['ssid'] === $ssid) { $n['signal'] = $signal; break; }
                    }
                    unset($n);
                    $seen[$ssid] = $signal;
                }
                continue;
            }
            $seen[$ssid] = $signal;
            $nets[] = [
                'ssid'     => $ssid,
                'signal'   => $signal,
                'bars'     => signal_bars($signal),
                'security' => $security ?: 'open',
                'open'     => ($security === '' || $security === '--'),
                'in_use'   => $inUse,
            ];
        }
        // Sortieren: verbunden zuerst, dann nach Signal absteigend
        usort($nets, fn($a, $b) => $b['in_use'] <=> $a['in_use'] ?: $b['signal'] <=> $a['signal']);

        echo json_encode(['ok' => true, 'networks' => $nets]);
        break;
    }

    // ── Verbinden ────────────────────────────────────────────────────────────
    case 'connect': {
        $ssid     = trim($_POST['ssid']     ?? '');
        $password = trim($_POST['password'] ?? '');
        $open     = ($_POST['open']         ?? '0') === '1';

        if ($ssid === '') {
            echo json_encode(['ok' => false, 'error' => 'SSID fehlt.']);
            break;
        }

        if ($open || $password === '') {
            $r = nmcli(['device', 'wifi', 'connect', $ssid]);
        } else {
            $r = nmcli(['device', 'wifi', 'connect', $ssid, 'password', $password]);
        }

        $success = $r['exit'] === 0 && !str_contains($r['raw'], 'Error');
        if ($success) {
            echo json_encode(['ok' => true, 'msg' => 'Verbunden mit ' . $ssid]);
        } else {
            $err = trim($r['raw']);
            // Häufige Fehlermeldungen vereinfachen
            if (str_contains($err, 'Secrets were required')) {
                $err = 'Falsches Passwort oder Verbindung fehlgeschlagen.';
            } elseif (str_contains($err, 'No network with SSID')) {
                $err = 'Netzwerk nicht gefunden. Bitte erneut scannen.';
            }
            echo json_encode(['ok' => false, 'error' => $err ?: 'Verbindung fehlgeschlagen.']);
        }
        break;
    }

    // ── Verbindung vergessen ─────────────────────────────────────────────────
    case 'forget': {
        $ssid = trim($_POST['ssid'] ?? '');
        if ($ssid === '') {
            echo json_encode(['ok' => false, 'error' => 'SSID fehlt.']);
            break;
        }
        $r = nmcli(['connection', 'delete', $ssid]);
        if ($r['exit'] === 0) {
            echo json_encode(['ok' => true, 'msg' => 'Verbindung "' . $ssid . '" gelöscht.']);
        } else {
            echo json_encode(['ok' => false, 'error' => trim($r['raw']) ?: 'Löschen fehlgeschlagen.']);
        }
        break;
    }

    // ── Trennen ───────────────────────────────────────────────────────────────
    case 'disconnect': {
        $dev = wlan_device();
        $r = nmcli(['device', 'disconnect', $dev]);
        if ($r['exit'] === 0) {
            echo json_encode(['ok' => true, 'msg' => 'WLAN getrennt.']);
        } else {
            echo json_encode(['ok' => false, 'error' => trim($r['raw']) ?: 'Trennen fehlgeschlagen.']);
        }
        break;
    }

    default:
        echo json_encode(['ok' => false, 'error' => 'Unbekannte Aktion: ' . htmlspecialchars($action)]);
        break;
}
