<?php
/**
 * BTC Catch Miner — Server-Sent Events (Live Withdraw Feed)
 * ===========================================================
 * Streams real-time withdrawal events to all connected clients.
 * Connect via:  GET events.php?since=DATETIME
 */

declare(strict_types=1);

require_once __DIR__ . '/config.php';
require_once __DIR__ . '/db.php';

// SSE Headers
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache, no-store, must-revalidate');
header('X-Accel-Buffering: no');        // Nginx: disable proxy buffering
header('X-Buffering: no');              // Some reverse proxies
header('Access-Control-Allow-Origin: *');
header('Pragma: no-cache');
header('Expires: 0');

// Kill ALL output buffering layers aggressively
ini_set('output_buffering', '0');
ini_set('zlib.output_compression', 'Off');
ini_set('implicit_flush', '1');
while (ob_get_level() > 0) { ob_end_clean(); }
ob_implicit_flush(true);
set_time_limit(90); // 90 sec — shorter cycles = more reliable reconnects

$since = $_GET['since'] ?? date('Y-m-d H:i:s', time() - 60);

function sendEvent(string $event, array $data): void {
    echo "event: {$event}\n";
    echo 'data: ' . json_encode($data) . "\n\n";
    flush();
    if (ob_get_level() > 0) ob_flush();
}

// Send initial connected event immediately
sendEvent('connected', ['time' => date('Y-m-d H:i:s')]);

// Use created_at >= since + track sent IDs to avoid duplicates.
// This prevents missing same-second withdrawals that `created_at > ?` would skip.
$lastCheck  = $since;
$sentIds    = [];     // withdrawal_ids already streamed this session
$iters      = 0;
$maxIters   = 85;     // reconnect after ~85 s for a fresh PHP process
$hbInterval = 15;    // heartbeat every 15 iters

while ($iters < $maxIters) {
    if (connection_aborted()) break;

    try {
        // >= so same-second records are never missed; deduplicate by ID in PHP
        $rows = DB::all(
            'SELECT w.withdrawal_id, w.username, w.photo_url, w.amount_sat, w.created_at,
                    COALESCE(p.first_name, w.username) AS first_name
             FROM   withdrawals w
             LEFT JOIN players p ON p.telegram_id = w.telegram_id
             WHERE  w.status = \'success\' AND w.created_at >= ?
             ORDER  BY w.created_at ASC
             LIMIT  20',
            [$lastCheck]
        );

        foreach ($rows as $row) {
            $wid = $row['withdrawal_id'];
            if (in_array($wid, $sentIds, true)) continue; // already sent

            $sentIds[] = $wid;
            if (count($sentIds) > 200) $sentIds = array_slice($sentIds, -100);

            // Advance lastCheck so future queries stay tight
            if ($row['created_at'] > $lastCheck) {
                $lastCheck = $row['created_at'];
            }

            sendEvent('withdrawal', [
                'id'         => $wid,
                'username'   => maskUsername($row['username']),
                'first_name' => $row['first_name'],
                'photo_url'  => $row['photo_url'],
                'amount_sat' => (int)$row['amount_sat'],
                'time'       => $row['created_at'],
            ]);
        }
    } catch (Exception $e) {
        // DB error — keep looping
    }

    // Heartbeat to detect dropped connections
    if ($iters > 0 && $iters % $hbInterval === 0) {
        echo ": heartbeat\n\n";
        flush();
        if (ob_get_level() > 0) ob_flush();
    }

    usleep(600000); // 0.6 s poll — 40% faster than 1 s, negligible server load
    $iters++;
}

// Tell client to reconnect
echo "event: reconnect\ndata: {}\n\n";
flush();

function maskUsername(string $name): string {
    if (strlen($name) <= 3) return $name . '***';
    return substr($name, 0, 3) . str_repeat('*', min(strlen($name) - 3, 4));
}
