<?php

require __DIR__ . '/../app/Core/Database.php';

use App\Core\Database;

$server = stream_socket_server('tcp://0.0.0.0:8081', $errno, $errstr);
if (!$server) {
    fwrite(STDERR, "WebSocket error: $errstr\n");
    exit(1);
}

stream_set_blocking($server, false);
$clients = [];
$lastEventId = 0;
echo "WebSocket listening on 0.0.0.0:8081\n";

while (true) {
    $read = array_merge([$server], array_column($clients, 'socket'));
    $write = $except = [];
    @stream_select($read, $write, $except, 1);

    foreach ($read as $socket) {
        if ($socket === $server) {
            $client = stream_socket_accept($server, 0);
            if ($client) {
                stream_set_blocking($client, false);
                $clients[(int) $client] = ['socket' => $client, 'handshake' => false];
            }
            continue;
        }

        $id = (int) $socket;
        $buffer = fread($socket, 2048);
        if ($buffer === '' || $buffer === false) {
            fclose($socket);
            unset($clients[$id]);
            continue;
        }

        if (!$clients[$id]['handshake']) {
            if (preg_match('/Sec-WebSocket-Key: (.*)\r\n/i', $buffer, $matches)) {
                $key = trim($matches[1]);
                $accept = base64_encode(sha1($key . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11', true));
                fwrite($socket, "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: $accept\r\n\r\n");
                $clients[$id]['handshake'] = true;
            }
        }
    }

    try {
        $db = Database::connection();
        $stmt = $db->prepare('SELECT id, match_id, event_type, points_home, points_away FROM match_events WHERE id > :id ORDER BY id ASC LIMIT 50');
        $stmt->execute(['id' => $lastEventId]);
        foreach ($stmt->fetchAll() as $event) {
            $lastEventId = (int) $event['id'];
            broadcast($clients, json_encode(['type' => 'match_event', 'data' => $event]));
        }
    } catch (Throwable $e) {
        usleep(300000);
    }
}

function broadcast(array &$clients, string $payload): void
{
    $frame = frame($payload);
    foreach ($clients as $id => $client) {
        if (!$client['handshake']) {
            continue;
        }
        if (@fwrite($client['socket'], $frame) === false) {
            fclose($client['socket']);
            unset($clients[$id]);
        }
    }
}

function frame(string $payload): string
{
    $length = strlen($payload);
    if ($length <= 125) {
        return chr(129) . chr($length) . $payload;
    }
    if ($length <= 65535) {
        return chr(129) . chr(126) . pack('n', $length) . $payload;
    }
    return chr(129) . chr(127) . pack('J', $length) . $payload;
}
