<?php
declare(strict_types=1);

use App\{Bootstrap, Queue, Utils};

require __DIR__ . '/../src/config.php'; // constants + tg-safe helpers
require __DIR__ . '/../src/Env.php';
require __DIR__ . '/../src/Logger.php';
require __DIR__ . '/../src/DB.php';
require __DIR__ . '/../src/Queue.php';
require __DIR__ . '/../src/Utils.php';
require __DIR__ . '/../src/Bootstrap.php';

$boot = new Bootstrap();
$log = $boot->log;
$poll = (int)(App\Env::get('QUEUE_POLL_INTERVAL_MS', '250'));
$once = in_array('--once', $argv ?? [], true);
$max = 0;
foreach (($argv ?? []) as $a) if (strpos($a, '--max=') === 0) $max = max(0, (int)substr($a, 6));
$processed = 0;

while (true) {
    $job = Queue::reserveNext($poll);
    if (!$job) {
        if ($once) break;
        usleep($poll * 1000);
        continue;
    }
    $payload = json_decode((string)$job['payload'], true) ?: [];
    try {
        switch ((string)$job['type']) {
            case 'send_document':
                $params = ['chat_id' => $payload['chat_id'], 'caption' => $payload['caption'] ?? null];
                if (is_file((string)($payload['file_path'] ?? ''))) $params['document'] = new CURLFile((string)$payload['file_path']);
                else throw new RuntimeException('file not found');
                Utils::tgRequest('sendDocument', $params);
                break;

            case 'send_notification':
                $params = [
                    'chat_id' => (int)$payload['chat_id'],
                    'text' => (string)($payload['text'] ?? ''),
                ];
                if (!empty($payload['parse_mode'])) $params['parse_mode'] = (string)$payload['parse_mode'];
                if (!empty($payload['reply_markup'])) $params['reply_markup'] = is_string($payload['reply_markup']) ? $payload['reply_markup'] : json_encode($payload['reply_markup'], JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
                Utils::tgRequest('sendMessage', $params);
                break;

            case 'broadcast_send':
                // Queue-safe per-recipient broadcast. The enqueue endpoint should split one user per job.
                $params = ['chat_id' => (int)$payload['chat_id']];
                if (!empty($payload['reply_markup'])) $params['reply_markup'] = is_string($payload['reply_markup']) ? $payload['reply_markup'] : json_encode($payload['reply_markup'], JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
                if (!empty($payload['photo'])) {
                    $params['photo'] = (string)$payload['photo'];
                    if (!empty($payload['caption'])) $params['caption'] = (string)$payload['caption'];
                    if (!empty($payload['parse_mode'])) $params['parse_mode'] = (string)$payload['parse_mode'];
                    Utils::tgRequest('sendPhoto', $params);
                } else {
                    $params['text'] = (string)($payload['text'] ?? '');
                    if (!empty($payload['parse_mode'])) $params['parse_mode'] = (string)$payload['parse_mode'];
                    Utils::tgRequest('sendMessage', $params);
                }
                usleep((int)App\Env::get('BROADCAST_WORKER_DELAY_US', '50000'));
                break;

            case 'cleanup_states':
                require_once __DIR__ . '/../src/GemAcc/StateService.php';
                $svc = new GemAcc\StateService(db());
                $svc->cleanupExpired();
                break;

            case 'stars_auto_cancel_order':
                $orderId = (int)($payload['order_id'] ?? 0);
                $userId = (int)($payload['user_id'] ?? 0);
                if ($orderId <= 0) throw new RuntimeException('invalid stars order id');
                $res = gemaccStarsAutoCancelPendingOrder(db(), $orderId, $userId > 0 ? $userId : null, true, true);
                if (empty($res['ok']) && empty($res['not_expired']) && empty($res['paid'])) {
                    throw new RuntimeException((string)($res['error'] ?? $res['message'] ?? 'stars auto cancel failed'));
                }
                break;

            case 'stars_auto_cancel_sweep':
                gemaccStarsAutoCancelExpired(db(), (int)($payload['limit'] ?? 50));
                break;

            default:
                throw new RuntimeException('unknown job type: ' . (string)$job['type']);
        }
        Queue::done((int)$job['id']);
        $processed++;
    } catch (Throwable $e) {
        $log->error('job failed', ['id' => $job['id'], 'type' => $job['type'], 'error' => $e->getMessage()]);
        Queue::fail((int)$job['id'], $e->getMessage(), min(3600, 30 * max(1, (int)$job['attempts'])));
    }
    if ($once || ($max > 0 && $processed >= $max)) break;
}
