<?php
// Minecraft 服务器查询类
class MinecraftServerQuery {
    private $socket;
    private $host;
    private $port;
    private $timeout;
    private $info = [];
    private $ping;

    public function __construct($host, $port = 25565, $timeout = 3) {
        $this->host = $host;
        $this->port = $port;
        $this->timeout = $timeout;
    }

    public function connect() {
        // 记录开始时间计算延迟
        $start = microtime(true);
        
        // 创建 socket 连接
        $this->socket = @fsockopen($this->host, $this->port, $errno, $errstr, $this->timeout);
        
        if (!$this->socket) {
            return false;
        }
        
        // 设置超时
        stream_set_timeout($this->socket, $this->timeout);
        
        // 发送握手包
        $this->sendHandshake();
        
        // 发送状态请求
        $this->sendStatusRequest();
        
        // 读取状态响应
        $this->readStatusResponse();
        
        // 计算延迟
        $this->ping = round((microtime(true) - $start) * 1000);
        
        // 关闭连接
        fclose($this->socket);
        
        return true;
    }
    
    private function sendHandshake() {
        $packet = pack('c', 0x00); // 包ID (Handshake)
        $packet .= pack('c', 0x04); // 协议版本 (4 for 1.7.2+)
        $packet .= pack('c', strlen($this->host)) . $this->host; // 服务器地址
        $packet .= pack('n', $this->port); // 服务器端口
        $packet .= pack('c', 0x01); // 下一步状态 (1 for Status)
        
        $packet = pack('c', strlen($packet)) . $packet; // 添加包长度前缀
        fwrite($this->socket, $packet);
    }
    
    private function sendStatusRequest() {
        $packet = pack('c', 0x00); // 包ID (Status Request)
        $packet = pack('c', strlen($packet)) . $packet;
        fwrite($this->socket, $packet);
    }
    
    private function readStatusResponse() {
        // 读取包长度
        $length = $this->readVarInt();
        
        // 读取包ID
        $packetID = $this->readVarInt();
        
        if ($packetID !== 0x00) {
            return false; // 不是状态响应包
        }
        
        // 读取JSON数据长度
        $jsonLength = $this->readVarInt();
        
        // 读取JSON数据
        $json = '';
        $bytesRead = 0;
        
        while ($bytesRead < $jsonLength) {
            $chunk = fread($this->socket, $jsonLength - $bytesRead);
            if ($chunk === false) break;
            $json .= $chunk;
            $bytesRead += strlen($chunk);
        }
        
        $this->info = json_decode($json, true);
        return true;
    }
    
    private function readVarInt() {
        $value = 0;
        $size = 0;
        $b;
        
        do {
            $b = ord(fgetc($this->socket));
            $value |= ($b & 0x7F) << ($size++ * 7);
            if ($size > 5) {
                throw new Exception('VarInt too big');
            }
        } while (($b & 0x80) == 0x80);
        
        return $value;
    }
    
    public function getInfo() {
        return $this->info;
    }
    
    public function getPing() {
        return $this->ping;
    }
    
    public function formatMotd($motd) {
        // 颜色代码映射
        $colors = [
            '0' => '#000000', '1' => '#0000AA', '2' => '#00AA00', '3' => '#00AAAA',
            '4' => '#AA0000', '5' => '#AA00AA', '6' => '#FFAA00', '7' => '#AAAAAA',
            '8' => '#555555', '9' => '#5555FF', 'a' => '#55FF55', 'b' => '#55FFFF',
            'c' => '#FF5555', 'd' => '#FF55FF', 'e' => '#FFFF55', 'f' => '#FFFFFF'
        ];
        
        // 格式化代码映射
        $formats = [
            'l' => 'font-weight:bold', // 粗体
            'm' => 'text-decoration:line-through', // 删除线
            'n' => 'text-decoration:underline', // 下划线
            'o' => 'font-style:italic', // 斜体
            'r' => '' // 重置
        ];
        
        $html = '';
        $currentStyles = [];
        $buffer = '';
        $chars = preg_split('//u', $motd, -1, PREG_SPLIT_NO_EMPTY);
        
        for ($i = 0; $i < count($chars); $i++) {
            $char = $chars[$i];
            
            if ($char === '§' && isset($chars[$i + 1])) {
                $code = $chars[$i + 1];
                $i++;
                
                // 处理颜色代码
                if (isset($colors[strtolower($code)])) {
                    if ($buffer !== '') {
                        $html .= $this->wrapWithStyles($buffer, $currentStyles);
                        $buffer = '';
                    }
                    $currentStyles['color'] = $colors[strtolower($code)];
                }
                // 处理格式代码
                elseif (isset($formats[strtolower($code)])) {
                    if ($buffer !== '') {
                        $html .= $this->wrapWithStyles($buffer, $currentStyles);
                        $buffer = '';
                    }
                    
                    if (strtolower($code) === 'r') {
                        $currentStyles = []; // 重置所有样式
                    } else {
                        $currentStyles[] = $formats[strtolower($code)];
                    }
                }
                // 忽略未知代码
                else {
                    $buffer .= $char . $code;
                }
            } else {
                $buffer .= $char;
            }
        }
        
        if ($buffer !== '') {
            $html .= $this->wrapWithStyles($buffer, $currentStyles);
        }
        
        // 处理换行符
        $html = str_replace("\n", "<br>", $html);
        
        return $html;
    }
    
    private function wrapWithStyles($text, $styles) {
        if (empty($styles)) {
            return htmlspecialchars($text);
        }
        
        $styleString = '';
        foreach ($styles as $key => $value) {
            if (is_numeric($key)) {
                $styleString .= $value . ';';
            } else {
                $styleString .= $key . ':' . $value . ';';
            }
        }
        
        return '<span style="' . $styleString . '">' . htmlspecialchars($text) . '</span>';
    }
}

// 处理API请求
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
    // 获取查询参数
    $host = isset($_GET['host']) ? $_GET['host'] : '';
    $port = isset($_GET['port']) ? (int)$_GET['port'] : 25565;
    
    // 验证输入
    if (empty($host)) {
        http_response_code(400);
        echo json_encode(['error' => 'Missing host parameter']);
        exit;
    }
    
    // 创建服务器查询实例
    $server = new MinecraftServerQuery($host, $port);
    
    try {
        // 尝试连接并获取信息
        $connected = $server->connect();
        
        if ($connected) {
            $info = $server->getInfo();
            $ping = $server->getPing();
            
            // 处理玩家列表
            $players = [];
            if (isset($info['players']['sample'])) {
                foreach ($info['players']['sample'] as $player) {
                    $players[] = $player['name'];
                }
            }
            
            // 格式化MOTD
            $motd = '';
            $formattedMotd = '';
            
            if (isset($info['description'])) {
                if (is_string($info['description'])) {
                    $motd = $info['description'];
                    $formattedMotd = $server->formatMotd($motd);
                } elseif (is_array($info['description']) && isset($info['description']['text'])) {
                    $motd = $info['description']['text'];
                    $formattedMotd = $server->formatMotd($motd);
                }
            }
            
            // 构建响应数据
            $response = [
                'online' => true,
                'host' => $host,
                'port' => $port,
                'ping' => $ping,
                'version' => $info['version']['name'] ?? 'Unknown',
                'protocol' => $info['version']['protocol'] ?? -1,
                'online_players' => $info['players']['online'] ?? 0,
                'max_players' => $info['players']['max'] ?? 0,
                'motd' => $motd,
                'formatted_motd' => $formattedMotd,
                'players' => $players
            ];
            
            echo json_encode($response);
        } else {
            http_response_code(500);
            echo json_encode([
                'online' => false,
                'error' => '无法连接到服务器',
                'host' => $host,
                'port' => $port
            ]);
        }
    } catch (Exception $e) {
        http_response_code(500);
        echo json_encode([
            'online' => false,
            'error' => $e->getMessage(),
            'host' => $host,
            'port' => $port
        ]);
    }
} else {
    http_response_code(405);
    echo json_encode(['error' => 'Method not allowed']);
}
?>