<?php
header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *');
header('Cache-Control: no-cache, must-revalidate');
header('Expires: 0');

ini_set('display_errors', 0);
error_reporting(0);

/**
 * Minecraft Server List Ping (protocole 1.7+)
 * Ref: https://wiki.vg/Server_List_Ping
 */
function pingMinecraftServer(string $host, int $port = 25565, int $timeout = 4): array {
    $result = [
        'online'      => false,
        'players'     => 0,
        'max_players' => 0,
        'version'     => '',
        'motd'        => '',
        'latency'     => null,
    ];

    $start = microtime(true);

    $socket = @fsockopen($host, $port, $errno, $errstr, $timeout);
    if (!$socket) {
        return $result;
    }

    stream_set_timeout($socket, $timeout);

    // ---- Handshake packet (0x00) ----
    $hostBytes = $host;
    $hostLen   = strlen($hostBytes);

    $handshakeData  = "\x00";                              // Packet ID 0x00
    $handshakeData .= varInt(47);                          // Protocol version (47 = 1.8, -1 non-spécifique)
    $handshakeData .= varInt($hostLen) . $hostBytes;       // Server address
    $handshakeData .= pack('n', $port);                    // Port (unsigned short big-endian)
    $handshakeData .= varInt(1);                           // Next state: 1 = status

    fwrite($socket, varInt(strlen($handshakeData)) . $handshakeData);

    // ---- Status Request (0x00, longueur 1) ----
    fwrite($socket, "\x01\x00");

    // ---- Lire la réponse ----
    $packetLen = readVarInt($socket);
    if ($packetLen <= 0) {
        fclose($socket);
        return $result;
    }

    // Lire l'ID du paquet (doit être 0x00)
    readVarInt($socket);

    // Lire la longueur de la chaîne JSON
    $strLen = readVarInt($socket);
    if ($strLen <= 0) {
        fclose($socket);
        return $result;
    }

    // Lire le JSON
    $json      = '';
    $remaining = $strLen;
    while ($remaining > 0 && !feof($socket)) {
        $chunk = fread($socket, min($remaining, 4096));
        if ($chunk === false || $chunk === '') break;
        $json      .= $chunk;
        $remaining -= strlen($chunk);
    }

    fclose($socket);

    $latency = (int) round((microtime(true) - $start) * 1000);
    $data    = @json_decode($json, true);

    if (!$data) {
        return $result;
    }

    // ---- Extraire le MOTD ----
    $motd = '';
    if (isset($data['description'])) {
        if (is_string($data['description'])) {
            $motd = $data['description'];
        } elseif (is_array($data['description'])) {
            $motd = $data['description']['text'] ?? '';
            // Concatener les extras
            if (!empty($data['description']['extra']) && is_array($data['description']['extra'])) {
                foreach ($data['description']['extra'] as $extra) {
                    $motd .= $extra['text'] ?? '';
                }
            }
        }
    }
    // Supprimer les codes couleur §X
    $motd = preg_replace('/§[0-9a-fk-orA-FK-OR]/u', '', $motd);
    $motd = trim(preg_replace('/\s+/', ' ', $motd));

    $result['online']      = true;
    $result['players']     = (int) ($data['players']['online'] ?? 0);
    $result['max_players'] = (int) ($data['players']['max']    ?? 0);
    $result['version']     = $data['version']['name'] ?? '';
    $result['motd']        = $motd;
    $result['latency']     = $latency;

    return $result;
}

/**
 * Encode un entier en VarInt Minecraft
 */
function varInt(int $value): string {
    $out = '';
    do {
        $byte   = $value & 0x7F;
        $value  = ($value >> 7) & PHP_INT_MAX; // shift sans signe
        if ($value !== 0) $byte |= 0x80;
        $out .= chr($byte);
    } while ($value !== 0);
    return $out;
}

/**
 * Lit un VarInt depuis un socket
 */
function readVarInt($socket): int {
    $value = 0;
    $shift = 0;
    do {
        $raw = fgetc($socket);
        if ($raw === false) return 0;
        $byte   = ord($raw);
        $value |= ($byte & 0x7F) << $shift;
        $shift += 7;
        if ($shift > 35) break; // sécurité anti-boucle infinie
    } while ($byte & 0x80);
    return $value;
}

// ======================================================
// Configuration des serveurs à pinger
// ======================================================
$servers = [
    [
        'name' => 'Serveur MC #1',
        'host' => 'nix.roulaise.net',
        'port' => 9191,
    ],
    [
        'name' => 'Serveur MC #2',
        'host' => 'nix.roulaise.net',
        'port' => 9292,
    ],
];

// ======================================================
// Ping tous les serveurs et retourner le résultat JSON
// ======================================================
$results = [];
foreach ($servers as $srv) {
    $ping      = pingMinecraftServer($srv['host'], $srv['port']);
    $results[] = array_merge([
        'name' => $srv['name'],
        'host' => $srv['host'],
        'port' => $srv['port'],
    ], $ping);
}

echo json_encode([
    'success'   => true,
    'servers'   => $results,
    'timestamp' => time(),
], JSON_UNESCAPED_UNICODE | JSON_NUMERIC_CHECK);
?>
