<?php
/**
 * ============================================================
 *  FAUCETPAY FAUCET BOT + MINI APP + v4.0
 *  Features: Faucet, Tasks, Quiz, Bonus, Leaderboard,
 *            Notifications, Auto-Channel-Post, Task Broadcast,
 *            FaucetPay Auto Payout
 *  File: f.php
 * ============================================================
 */

// ==================== CONFIG ====================
define('DB_HOST', 'localhost');
define('DB_NAME', 'zkrdgzqdlb_fucct');
define('DB_USER', 'zkrdgzqdlb_fucct');
define('DB_PASS', 'zkrdgzqdlb_fucct');

define('BOT_TOKEN',    '7994389214:AAHO5Vmfl44Q5YX9pchff0F3U87umCegYxQ');
define('BOT_USERNAME', 'Taskearnc_bot');
define('ADMIN_ID',     1197843847);

define('COIN_SYMBOL',   'USDT');
define('COIN_DECIMALS', 6);

date_default_timezone_set('Asia/Dhaka');
error_reporting(E_ALL);
ini_set('display_errors', 0);
ini_set('log_errors', 1);
ini_set('error_log', __DIR__ . '/faucet_error.log');

// ==================== DATABASE ====================
function db() {
    static $pdo = null;
    if ($pdo === null) {
        $pdo = new PDO("mysql:host=" . DB_HOST . ";dbname=" . DB_NAME . ";charset=utf8mb4",
            DB_USER, DB_PASS, [
                PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
                PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
                PDO::ATTR_EMULATE_PREPARES => false,
            ]);
    }
    return $pdo;
}
function q($sql, $params = []) {
    $s = db()->prepare($sql);
    $s->execute($params);
    return $s;
}

// ==================== INSTALL ====================
function install() {
    $pdo = db();

    $pdo->exec("CREATE TABLE IF NOT EXISTS users (
        id INT AUTO_INCREMENT PRIMARY KEY,
        chat_id VARCHAR(50) UNIQUE NOT NULL,
        username VARCHAR(100),
        first_name VARCHAR(100),
        faucetpay_email VARCHAR(150) DEFAULT NULL,
        twitter_username VARCHAR(100) DEFAULT NULL,
        balance DECIMAL(20,8) DEFAULT 0,
        total_claimed DECIMAL(20,8) DEFAULT 0,
        total_withdrawn DECIMAL(20,8) DEFAULT 0,
        total_task_earned DECIMAL(20,8) DEFAULT 0,
        total_bonus_earned DECIMAL(20,8) DEFAULT 0,
        total_quiz_earned DECIMAL(20,8) DEFAULT 0,
        claims_count INT DEFAULT 0,
        last_claim DATETIME NULL,
        bonus_streak INT DEFAULT 0,
        last_bonus DATE NULL,
        referral_code VARCHAR(20) UNIQUE,
        referred_by INT NULL,
        is_banned TINYINT DEFAULT 0,
        state VARCHAR(50) DEFAULT NULL,
        temp_data VARCHAR(255) DEFAULT NULL,
        created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
        INDEX idx_chat (chat_id)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");

    $pdo->exec("CREATE TABLE IF NOT EXISTS claims (
        id INT AUTO_INCREMENT PRIMARY KEY,
        user_id INT NOT NULL,
        amount DECIMAL(20,8) NOT NULL,
        ip VARCHAR(45),
        created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
        FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
        INDEX idx_ut (user_id, created_at)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");

    $pdo->exec("CREATE TABLE IF NOT EXISTS withdrawals (
        id INT AUTO_INCREMENT PRIMARY KEY,
        user_id INT NOT NULL,
        amount DECIMAL(20,8) NOT NULL,
        faucetpay_email VARCHAR(150) NOT NULL,
        tx_id VARCHAR(100),
        status ENUM('pending','processing','completed','failed','rejected') DEFAULT 'pending',
        error TEXT,
        idempotency_key VARCHAR(100) UNIQUE,
        created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
        processed_at DATETIME NULL,
        FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");

    $pdo->exec("CREATE TABLE IF NOT EXISTS tasks (
        id INT AUTO_INCREMENT PRIMARY KEY,
        task_name VARCHAR(200) NOT NULL,
        task_description TEXT,
        chat_username VARCHAR(100) NOT NULL,
        points DECIMAL(20,8) NOT NULL,
        is_active TINYINT DEFAULT 1,
        created_at DATETIME DEFAULT CURRENT_TIMESTAMP
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");

    $pdo->exec("CREATE TABLE IF NOT EXISTS user_tasks (
        id INT AUTO_INCREMENT PRIMARY KEY,
        user_id INT NOT NULL,
        task_id INT NOT NULL,
        points_earned DECIMAL(20,8) NOT NULL,
        completed_at DATETIME DEFAULT CURRENT_TIMESTAMP,
        UNIQUE KEY unique_user_task (user_id, task_id),
        FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
        FOREIGN KEY (task_id) REFERENCES tasks(id) ON DELETE CASCADE
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");

    $pdo->exec("CREATE TABLE IF NOT EXISTS twitter_tasks (
        id INT AUTO_INCREMENT PRIMARY KEY,
        task_name VARCHAR(200) NOT NULL,
        task_description TEXT,
        twitter_url VARCHAR(500) NOT NULL,
        task_type ENUM('follow','like','retweet','comment','custom') DEFAULT 'follow',
        points DECIMAL(20,8) NOT NULL,
        is_active TINYINT DEFAULT 1,
        created_at DATETIME DEFAULT CURRENT_TIMESTAMP
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");

    $pdo->exec("CREATE TABLE IF NOT EXISTS user_twitter_tasks (
        id INT AUTO_INCREMENT PRIMARY KEY,
        user_id INT NOT NULL,
        twitter_task_id INT NOT NULL,
        twitter_username VARCHAR(100),
        status ENUM('pending','approved','rejected') DEFAULT 'pending',
        admin_note TEXT,
        completed_at DATETIME DEFAULT CURRENT_TIMESTAMP,
        reviewed_at DATETIME NULL,
        UNIQUE KEY unique_user_tw (user_id, twitter_task_id),
        FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
        FOREIGN KEY (twitter_task_id) REFERENCES twitter_tasks(id) ON DELETE CASCADE
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");

    $pdo->exec("CREATE TABLE IF NOT EXISTS quizzes (
        id INT AUTO_INCREMENT PRIMARY KEY,
        question TEXT NOT NULL,
        options JSON NOT NULL,
        correct_answer CHAR(1) NOT NULL,
        points DECIMAL(20,8) NOT NULL DEFAULT 0.01,
        is_active TINYINT DEFAULT 1,
        created_at DATETIME DEFAULT CURRENT_TIMESTAMP
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");

    $pdo->exec("CREATE TABLE IF NOT EXISTS user_quizzes (
        id INT AUTO_INCREMENT PRIMARY KEY,
        user_id INT NOT NULL,
        quiz_id INT NOT NULL,
        answer CHAR(1) NOT NULL,
        is_correct TINYINT DEFAULT 0,
        points_earned DECIMAL(20,8) DEFAULT 0,
        attempted_at DATETIME DEFAULT CURRENT_TIMESTAMP,
        UNIQUE KEY unique_user_quiz (user_id, quiz_id),
        FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
        FOREIGN KEY (quiz_id) REFERENCES quizzes(id) ON DELETE CASCADE
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");

    $pdo->exec("CREATE TABLE IF NOT EXISTS notifications (
        id INT AUTO_INCREMENT PRIMARY KEY,
        user_id INT NOT NULL,
        title VARCHAR(200) NOT NULL,
        message TEXT NOT NULL,
        type VARCHAR(30) DEFAULT 'info',
        is_read TINYINT DEFAULT 0,
        created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
        FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
        INDEX idx_user_read (user_id, is_read)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");

    $pdo->exec("CREATE TABLE IF NOT EXISTS settings (
        id INT AUTO_INCREMENT PRIMARY KEY,
        setting_key VARCHAR(100) UNIQUE NOT NULL,
        setting_value TEXT,
        updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");

    $defaults = [
        ['faucetpay_api_key', ''],
        ['faucetpay_currency', 'USDT'],
        ['claim_amount', '0.01'],
        ['claim_cooldown', '3600'],
        ['min_withdraw', '0.5'],
        ['referral_bonus', '0.005'],
        ['faucetpay_enabled', '1'],
        ['withdrawals_enabled', '1'],
        ['tasks_enabled', '1'],
        ['twitter_tasks_enabled', '1'],
        ['daily_bonus_enabled', '1'],
        ['quiz_enabled', '1'],
        ['leaderboard_enabled', '1'],
        // ============ NEW: CHANNEL SETTINGS ============
        ['payment_channel', ''],           // @channel or -100xxx
        ['task_channel', ''],              // @channel or -100xxx
        ['broadcast_on_task', '1'],        // 1=on, 0=off
        ['announce_payments', '1'],        // 1=on, 0=off
        ['announce_task_complete', '1'],   // 1=on, 0=off
    ];
    $stmt = $pdo->prepare("INSERT IGNORE INTO settings (setting_key, setting_value) VALUES (?, ?)");
    foreach ($defaults as $d) $stmt->execute($d);

    $sampleQuizzes = [
        ['What is Bitcoin?', json_encode(['A'=>'A company','B'=>'A cryptocurrency','C'=>'A bank','D'=>'A game']), 'B', 0.005],
        ['Which network is USDT BEP-20 on?', json_encode(['A'=>'Ethereum','B'=>'Tron','C'=>'BSC','D'=>'Solana']), 'C', 0.005],
        ['What is Telegram?', json_encode(['A'=>'Messaging app','B'=>'Bank','C'=>'Browser','D'=>'OS']), 'A', 0.005],
        ['FaucetPay is a?', json_encode(['A'=>'Bank','B'=>'Micropayment platform','C'=>'Exchange','D'=>'Wallet only']), 'B', 0.005],
    ];
    $stmt = $pdo->prepare("INSERT IGNORE INTO quizzes (question, options, correct_answer, points) VALUES (?, ?, ?, ?)");
    foreach ($sampleQuizzes as $sq) { try { $stmt->execute($sq); } catch (Exception $e) {} }

    $alters = [
        "ALTER TABLE users ADD COLUMN IF NOT EXISTS total_bonus_earned DECIMAL(20,8) DEFAULT 0",
        "ALTER TABLE users ADD COLUMN IF NOT EXISTS total_quiz_earned DECIMAL(20,8) DEFAULT 0",
        "ALTER TABLE users ADD COLUMN IF NOT EXISTS bonus_streak INT DEFAULT 0",
        "ALTER TABLE users ADD COLUMN IF NOT EXISTS last_bonus DATE NULL",
    ];
    foreach ($alters as $a) { try { $pdo->exec($a); } catch (Exception $e) {} }

    echo "✅ All tables created! Remove ?install=1 from URL.";
    exit;
}

// ==================== SETTINGS ====================
function getSetting($key, $default = '') {
    static $cache = null;
    if ($cache === null) {
        $cache = [];
        foreach (q("SELECT setting_key, setting_value FROM settings")->fetchAll() as $r)
            $cache[$r['setting_key']] = $r['setting_value'];
    }
    return $cache[$key] ?? $default;
}
function updateSetting($key, $value) {
    q("INSERT INTO settings (setting_key, setting_value) VALUES (?, ?)
       ON DUPLICATE KEY UPDATE setting_value = ?", [$key, $value, $value]);
}

// ==================== TELEGRAM API ====================
function tg($method, $data = []) {
    $url = "https://api.telegram.org/bot" . BOT_TOKEN . "/$method";
    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true,
        CURLOPT_POSTFIELDS => http_build_query($data), CURLOPT_TIMEOUT => 15,
    ]);
    $res = curl_exec($ch); curl_close($ch);
    return json_decode($res, true);
}
function send($chatId, $text, $kb = null) {
    $d = ['chat_id' => $chatId, 'text' => $text, 'parse_mode' => 'HTML', 'disable_web_page_preview' => true];
    if ($kb) $d['reply_markup'] = json_encode($kb);
    return tg('sendMessage', $d);
}
function editMessage($chatId, $msgId, $text, $kb = null) {
    $d = ['chat_id' => $chatId, 'message_id' => $msgId, 'text' => $text, 'parse_mode' => 'HTML', 'disable_web_page_preview' => true];
    if ($kb) $d['reply_markup'] = json_encode($kb);
    return tg('editMessageText', $d);
}
function isUserInChat($userId, $chatUsername) {
    $chat = trim((string)$chatUsername);
    if ($chat !== '' && strpos($chat, '@') !== 0 && strpos($chat, '-') !== 0 && !is_numeric($chat)) {
        $chat = '@' . $chat;
    }
    $r = tg('getChatMember', ['chat_id' => $chat, 'user_id' => $userId]);
    @file_put_contents(__DIR__ . '/chat_check.log',
        date('c') . " | user={$userId} chat={$chat} resp=" . json_encode($r) . "\n", FILE_APPEND);
    if (empty($r['ok'])) return false;
    $status = strtolower($r['result']['status'] ?? '');
    return in_array($status, ['creator', 'administrator', 'member', 'restricted'], true);
}

// ==================== CHANNEL POST HELPERS ====================
function postToChannel($channel, $text, $kb = null) {
    $ch = trim($channel);
    if (empty($ch)) return false;
    if (strpos($ch, '@') !== 0 && strpos($ch, '-') !== 0 && !is_numeric($ch)) $ch = '@' . $ch;
    $r = send($ch, $text, $kb);
    if (empty($r['ok'])) {
        @file_put_contents(__DIR__ . '/channel_error.log',
            date('c') . " | channel={$ch} err=" . json_encode($r) . "\n", FILE_APPEND);
    }
    return !empty($r['ok']);
}

function announcePayment($user, $amount, $tx, $email) {
    if (getSetting('announce_payments', '1') != '1') return;
    $channel = getSetting('payment_channel', '');
    if (empty($channel)) return;

    $msg = "💰 <b>Payment Sent!</b>\n\n";
    $msg .= "━━━━━━━━━━━━━━━━━━━━━\n";
    $msg .= "👤 User: " . htmlspecialchars($user['first_name'] ?: 'User');
    if ($user['username']) $msg .= " (@" . htmlspecialchars($user['username']) . ")";
    $msg .= "\n";
    $msg .= "💵 Amount: <b>" . fmt($amount) . " " . COIN_SYMBOL . "</b>\n";
    $msg .= "📧 To: <code>" . htmlspecialchars($email) . "</code>\n";
    $msg .= "🆔 TX: <code>" . htmlspecialchars(substr($tx, 0, 20)) . "...</code>\n";
    $msg .= "⏰ " . date('d M Y, H:i') . "\n";
    $msg .= "━━━━━━━━━━━━━━━━━━━━━\n";
    $msg .= "✅ Auto Withdraw System";

    postToChannel($channel, $msg);
}

function announceTaskComplete($user, $taskName, $points, $type = 'telegram') {
    if (getSetting('announce_task_complete', '1') != '1') return;
    $channel = getSetting('task_channel', '');
    if (empty($channel)) return;

    $typeEmoji = $type === 'twitter' ? '🐦' : '📱';
    $msg = "🎯 <b>Task Completed!</b>\n\n";
    $msg .= "━━━━━━━━━━━━━━━━━━━━━\n";
    $msg .= "👤 User: " . htmlspecialchars($user['first_name'] ?: 'User');
    if ($user['username']) $msg .= " (@" . htmlspecialchars($user['username']) . ")";
    $msg .= "\n";
    $msg .= "{$typeEmoji} Task: <b>" . htmlspecialchars($taskName) . "</b>\n";
    $msg .= "💰 Reward: <b>" . fmt($points) . " " . COIN_SYMBOL . "</b>\n";
    $msg .= "⏰ " . date('d M Y, H:i') . "\n";
    $msg .= "━━━━━━━━━━━━━━━━━━━━━";

    postToChannel($channel, $msg);
}

function announceNewTask($type, $task) {
    if (getSetting('broadcast_on_task', '1') != '1') return;
    $typeEmoji = $type === 'twitter' ? '🐦' : '📱';
    $typeLabel = $type === 'twitter' ? 'Twitter' : 'Telegram';
    $channel = getSetting('task_channel', '');
    if (!empty($channel)) {
        $msg = "🆕 <b>New {$typeLabel} Task Added!</b>\n\n";
        $msg .= "━━━━━━━━━━━━━━━━━━━━━\n";
        $msg .= "{$typeEmoji} <b>" . htmlspecialchars($task['task_name']) . "</b>\n";
        $msg .= "📝 " . htmlspecialchars($task['task_description']) . "\n";
        $msg .= "💰 Reward: <b>" . fmt($task['points']) . " " . COIN_SYMBOL . "</b>\n";
        $msg .= "━━━━━━━━━━━━━━━━━━━━━\n";
        $msg .= "🚀 Open bot to complete: @" . BOT_USERNAME;
        postToChannel($channel, $msg);
    }
}

function broadcastNewTaskToAllUsers($type, $task) {
    if (getSetting('broadcast_on_task', '1') != '1') return;

    $typeEmoji = $type === 'twitter' ? '🐦' : '📱';
    $typeLabel = $type === 'twitter' ? 'Twitter' : 'Telegram';

    $users = q("SELECT chat_id, id FROM users WHERE is_banned = 0")->fetchAll();
    $msg = "🆕 <b>New {$typeLabel} Task!</b>\n\n";
    $msg .= "{$typeEmoji} <b>" . htmlspecialchars($task['task_name']) . "</b>\n";
    $msg .= "📝 " . htmlspecialchars($task['task_description']) . "\n";
    $msg .= "💰 Reward: <b>" . fmt($task['points']) . " " . COIN_SYMBOL . "</b>\n\n";
    $msg .= "🎯 Complete this task in the Mini App to earn!";

    $count = 0;
    foreach ($users as $u) {
        $r = send($u['chat_id'], $msg);
        if (!empty($r['ok'])) $count++;
        usleep(50000); // 0.05s rate limit
    }
    @file_put_contents(__DIR__ . '/broadcast.log',
        date('c') . " | type={$type} task=" . $task['task_name'] . " sent={$count}/" . count($users) . "\n", FILE_APPEND);
}

// ==================== NOTIFICATION HELPER ====================
function addNotification($userId, $title, $message, $type = 'info') {
    try {
        q("INSERT INTO notifications (user_id, title, message, type) VALUES (?, ?, ?, ?)",
          [$userId, $title, $message, $type]);
    } catch (Exception $e) {}
}

// ==================== VALIDATE MINI APP ====================
function validateWebAppData($initData) {
    parse_str($initData, $data);
    if (!isset($data['hash'])) return null;
    $receivedHash = $data['hash']; unset($data['hash']);
    ksort($data);
    $str = [];
    foreach ($data as $k => $v) $str[] = "$k=$v";
    $str = implode("\n", $str);
    $secret = hash_hmac('sha256', BOT_TOKEN, 'WebAppData', true);
    $calc = hash_hmac('sha256', $str, $secret);
    if (!hash_equals($calc, $receivedHash)) return null;
    return json_decode($data['user'] ?? '{}', true);
}

// ==================== HELPERS ====================
function genRef() { return strtoupper(substr(bin2hex(random_bytes(4)), 0, 8)); }
function getUserByChat($chatId) { return q("SELECT * FROM users WHERE chat_id = ?", [$chatId])->fetch(); }
function getUserByRef($code) { return q("SELECT * FROM users WHERE referral_code = ?", [$code])->fetch(); }
function getUserById($id) { return q("SELECT * FROM users WHERE id = ?", [$id])->fetch(); }
function fmt($n) { return number_format((float)$n, 8, '.', ''); }

function ensureUser($tgUser, $refCode = null) {
    $chatId = $tgUser['id'];
    $u = getUserByChat($chatId);
    if ($u) return $u;
    $refBy = null;
    if ($refCode) { $ref = getUserByRef($refCode); if ($ref) $refBy = $ref['id']; }
    q("INSERT INTO users (chat_id, username, first_name, referral_code, referred_by) VALUES (?, ?, ?, ?, ?)",
      [$chatId, $tgUser['username'] ?? '', $tgUser['first_name'] ?? '', genRef(), $refBy]);
    return getUserByChat($chatId);
}

// ==================== FAUCETPAY API v2 ====================
function faucetPaySend($toEmail, $amount, $currency = null) {
    $apiKey = getSetting('faucetpay_api_key');
    if (empty($apiKey)) return ['ok' => false, 'error' => 'FaucetPay API key not set'];
    $currency = $currency ?: getSetting('faucetpay_currency', 'USDT');
    $decimals = ['BTC' => 8, 'ETH' => 18, 'USDT' => 6, 'DOGE' => 8, 'LTC' => 8, 'TRX' => 6];
    $dec = $decimals[$currency] ?? 8;
    $amountInt = (int) round($amount * pow(10, $dec));
    $idem = 'fp_' . bin2hex(random_bytes(12));
    $payload = json_encode([
        'idempotency_key' => $idem, 'to' => $toEmail,
        'amount' => $amountInt, 'currency' => $currency,
    ]);
    $ch = curl_init('https://faucetpay.io/api/v2/send');
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_POSTFIELDS => $payload,
        CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Authorization: Bearer ' . $apiKey],
        CURLOPT_TIMEOUT => 30,
    ]);
    $res = curl_exec($ch); $http = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch);
    $json = json_decode($res, true);
    if (($http == 200 || $http == 201) && !empty($json['success']))
        return ['ok' => true, 'tx_id' => $json['payout_id'] ?? $json['tx_id'] ?? 'sent'];
    return ['ok' => false, 'error' => $json['message'] ?? $json['error'] ?? 'HTTP ' . $http];
}

// ==================== BOT HANDLER ====================
function handleBot($update) {
    if (!isset($update['message'])) return;
    $m = $update['message'];
    $chatId = $m['chat']['id'];
    $text = $m['text'] ?? '';
    $from = $m['from'];
    $userId = $from['id'];
    if (($m['chat']['type'] ?? 'private') !== 'private') return;

    $refCode = null;
    if (preg_match('/^\/start\s+(\w+)/', $text, $mm)) $refCode = $mm[1];
    $user = ensureUser($from, $refCode);
    if (!$user) return;

    if ($text == '/cancel') {
        q("UPDATE users SET state = NULL, temp_data = NULL WHERE id = ?", [$user['id']]);
        send($chatId, "✅ Cancelled!", mainMenuKeyboard($userId)); return;
    }

    if ($user['state']) { handleState($chatId, $text, $user, $userId); return; }

    $appUrl = (isset($_SERVER['HTTPS']) ? 'https' : 'http') . '://' . $_SERVER['HTTP_HOST'] . parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);

    if ($userId == ADMIN_ID) {
        if ($text == '/admin' || $text == '🔐 Admin Panel') { adminPanel($chatId, $userId); return; }
        if ($text == '⚙️ FaucetPay Settings') { faucetPaySettings($chatId, $userId); return; }
        if ($text == '📢 Channel Settings') { channelSettings($chatId, $userId); return; }
        if ($text == '🎯 Task Management') { taskManagement($chatId, $userId); return; }
        if ($text == '📝 Quiz Management') { quizManagement($chatId, $userId); return; }
        if ($text == '📊 Bot Stats') { botStats($chatId, $userId); return; }
        if ($text == '👥 Users') { listUsers($chatId, $userId); return; }
        if ($text == '💰 Pending Withdrawals') { pendingWithdrawals($chatId, $userId); return; }
        if ($text == '🐦 Pending Twitter Tasks') { pendingTwitterSubmissions($chatId, $userId); return; }
        if ($text == '⬅️ Main Menu') { send($chatId, "🏠 Main Menu", mainMenuKeyboard($userId)); return; }
    }

    if (strpos($text, '/start') === 0) {
        $kb = ['inline_keyboard' => [
            [['text' => "🚀 Open Faucet App", 'web_app' => ['url' => $appUrl]]],
            [['text' => "💰 Balance", 'callback_data' => 'bal'],
             ['text' => "🔗 Referral", 'callback_data' => 'ref']],
        ]];
        $msg = "💵 <b>Welcome to " . COIN_SYMBOL . " Faucet!</b>\n\n";
        $msg .= "💰 Claim free every " . (getSetting('claim_cooldown', 3600)/60) . " min\n";
        $msg .= "🔥 Daily bonus streak\n";
        $msg .= "📝 Answer quizzes for rewards\n";
        $msg .= "🎯 Complete tasks to earn more\n";
        $msg .= "💸 Auto withdraw via FaucetPay\n\n👇 Tap below";
        send($chatId, $msg, $kb);
    }
    elseif ($text == '/balance' || $text == '💰 Balance') {
        send($chatId, "💰 <b>Balance</b>\n\n💎 " . fmt($user['balance']) . " " . COIN_SYMBOL);
    }
    elseif ($text == '/referral' || $text == '🔗 Referral') {
        $link = "https://t.me/" . BOT_USERNAME . "?start=" . $user['referral_code'];
        send($chatId, "🔗 Your Referral Link:\n<code>$link</code>\n\n💰 Bonus: " . getSetting('referral_bonus') . " " . COIN_SYMBOL);
    }
    else send($chatId, "❓ Use the buttons below:", mainMenuKeyboard($userId));
}

// ==================== STATE HANDLER ====================
function handleState($chatId, $text, $user, $userId) {
    $state = $user['state'];
    if ($userId != ADMIN_ID) { q("UPDATE users SET state = NULL WHERE id = ?", [$user['id']]); return; }

    if ($state == 'edit_fp_key') {
        $key = trim($text);
        if (strlen($key) < 20) { send($chatId, "❌ Too short. Try again or /cancel"); return; }
        updateSetting('faucetpay_api_key', $key);
        q("UPDATE users SET state = NULL WHERE id = ?", [$user['id']]);
        send($chatId, "✅ API Key saved!"); faucetPaySettings($chatId, $userId);
    }
    elseif ($state == 'edit_fp_currency') {
        $c = strtoupper(trim($text));
        if (!in_array($c, ['USDT','BTC','DOGE','LTC','ETH','TRX'])) { send($chatId, "❌ Invalid. Try again or /cancel"); return; }
        updateSetting('faucetpay_currency', $c);
        q("UPDATE users SET state = NULL WHERE id = ?", [$user['id']]);
        send($chatId, "✅ Currency: $c"); faucetPaySettings($chatId, $userId);
    }
    elseif ($state == 'edit_claim_amount') {
        if (!is_numeric($text) || $text <= 0) { send($chatId, "❌ Invalid. Try /cancel"); return; }
        updateSetting('claim_amount', (string)(float)$text);
        q("UPDATE users SET state = NULL WHERE id = ?", [$user['id']]);
        send($chatId, "✅ Claim: $text " . COIN_SYMBOL); faucetPaySettings($chatId, $userId);
    }
    elseif ($state == 'edit_cooldown') {
        if (!is_numeric($text) || (int)$text < 60) { send($chatId, "❌ Min 60s. Try /cancel"); return; }
        updateSetting('claim_cooldown', (string)(int)$text);
        q("UPDATE users SET state = NULL WHERE id = ?", [$user['id']]);
        send($chatId, "✅ Cooldown: {$text}s"); faucetPaySettings($chatId, $userId);
    }
    elseif ($state == 'edit_min_withdraw') {
        if (!is_numeric($text) || $text <= 0) { send($chatId, "❌ Invalid. Try /cancel"); return; }
        updateSetting('min_withdraw', (string)(float)$text);
        q("UPDATE users SET state = NULL WHERE id = ?", [$user['id']]);
        send($chatId, "✅ Min withdraw: $text"); faucetPaySettings($chatId, $userId);
    }
    // ============ CHANNEL SETTINGS ============
    elseif ($state == 'edit_payment_channel') {
        $ch = trim($text);
        if ($ch == '0' || strtolower($ch) == 'off' || strtolower($ch) == 'none') {
            updateSetting('payment_channel', '');
            send($chatId, "✅ Payment channel DISABLED");
        } else {
            if (strpos($ch, '@') !== 0 && strpos($ch, '-') !== 0 && !is_numeric($ch)) $ch = '@' . $ch;
            $test = send($ch, "🧪 Test message from bot — Payment channel is working ✅");
            if (empty($test['ok'])) {
                send($chatId, "❌ Test failed: " . ($test['description'] ?? 'unknown') . "\n\n<b>কারণ:</b>\n• Bot কে channel এ admin করতে হবে\n• Channel username ভুল\n• Bot এ message post permission নেই\n\nআবার চেষ্টা করুন বা /cancel");
                return;
            }
            updateSetting('payment_channel', $ch);
            send($chatId, "✅ Payment channel set: <code>{$ch}</code>\n🧪 Test message posted!");
        }
        q("UPDATE users SET state = NULL WHERE id = ?", [$user['id']]);
        channelSettings($chatId, $userId);
    }
    elseif ($state == 'edit_task_channel') {
        $ch = trim($text);
        if ($ch == '0' || strtolower($ch) == 'off' || strtolower($ch) == 'none') {
            updateSetting('task_channel', '');
            send($chatId, "✅ Task channel DISABLED");
        } else {
            if (strpos($ch, '@') !== 0 && strpos($ch, '-') !== 0 && !is_numeric($ch)) $ch = '@' . $ch;
            $test = send($ch, "🧪 Test message from bot — Task channel is working ✅");
            if (empty($test['ok'])) {
                send($chatId, "❌ Test failed: " . ($test['description'] ?? 'unknown') . "\n\n<b>কারণ:</b>\n• Bot কে channel এ admin করতে হবে\n• Channel username ভুল\n• Bot এ message post permission নেই\n\nআবার চেষ্টা করুন বা /cancel");
                return;
            }
            updateSetting('task_channel', $ch);
            send($chatId, "✅ Task channel set: <code>{$ch}</code>\n🧪 Test message posted!");
        }
        q("UPDATE users SET state = NULL WHERE id = ?", [$user['id']]);
        channelSettings($chatId, $userId);
    }
    // ============ TASK/QUIZ ============
    elseif ($state == 'add_tg_task') {
        $parts = array_map('trim', explode('|', $text));
        if (count($parts) < 4) { send($chatId, "❌ Format: Name | Description | @channel | Reward\nTry again or /cancel"); return; }
        $ch = $parts[2];
        if (strpos($ch, '@') !== 0 && strpos($ch, '-') !== 0 && !is_numeric($ch)) $ch = '@' . $ch;
        if (!is_numeric($parts[3]) || $parts[3] <= 0) { send($chatId, "❌ Invalid reward. Try again"); return; }
        q("INSERT INTO tasks (task_name, task_description, chat_username, points) VALUES (?, ?, ?, ?)",
          [$parts[0], $parts[1], $ch, (float)$parts[3]]);
        q("UPDATE users SET state = NULL WHERE id = ?", [$user['id']]);

        $task = ['task_name' => $parts[0], 'task_description' => $parts[1], 'points' => (float)$parts[3]];
        send($chatId, "✅ Telegram Task added!\n📌 {$parts[0]}\n💎 {$parts[3]} " . COIN_SYMBOL . "\n📢 $ch\n\n⏳ Broadcasting to all users...");

        // Announce to channel + all users
        announceNewTask('telegram', $task);
        broadcastNewTaskToAllUsers('telegram', $task);

        send($chatId, "✅ Broadcast complete!");
        taskManagement($chatId, $userId);
    }
    elseif ($state == 'add_tw_task') {
        $parts = array_map('trim', explode('|', $text));
        if (count($parts) < 5) { send($chatId, "❌ Format: Name | Description | URL | Type | Reward\nTry again or /cancel"); return; }
        $types = ['follow','like','retweet','comment','custom'];
        $type = strtolower($parts[3]);
        if (!in_array($type, $types)) $type = 'custom';
        if (!filter_var($parts[2], FILTER_VALIDATE_URL)) { send($chatId, "❌ Invalid URL. Try again"); return; }
        if (!is_numeric($parts[4]) || $parts[4] <= 0) { send($chatId, "❌ Invalid reward"); return; }
        q("INSERT INTO twitter_tasks (task_name, task_description, twitter_url, task_type, points) VALUES (?, ?, ?, ?, ?)",
          [$parts[0], $parts[1], $parts[2], $type, (float)$parts[4]]);
        q("UPDATE users SET state = NULL WHERE id = ?", [$user['id']]);

        $task = ['task_name' => $parts[0], 'task_description' => $parts[1], 'points' => (float)$parts[4]];
        send($chatId, "✅ Twitter Task added!\n📌 {$parts[0]}\n💎 {$parts[4]} " . COIN_SYMBOL . "\n\n⏳ Broadcasting...");

        announceNewTask('twitter', $task);
        broadcastNewTaskToAllUsers('twitter', $task);

        send($chatId, "✅ Broadcast complete!");
        taskManagement($chatId, $userId);
    }
    elseif ($state == 'add_quiz') {
        $parts = array_map('trim', explode('|', $text));
        if (count($parts) < 7) { send($chatId, "❌ Format: Question | A | B | C | D | Correct(A/B/C/D) | Reward\nTry again or /cancel"); return; }
        $correct = strtoupper($parts[5]);
        if (!in_array($correct, ['A','B','C','D'])) { send($chatId, "❌ Correct must be A/B/C/D"); return; }
        if (!is_numeric($parts[6]) || $parts[6] <= 0) { send($chatId, "❌ Invalid reward"); return; }
        $opts = json_encode(['A'=>$parts[1],'B'=>$parts[2],'C'=>$parts[3],'D'=>$parts[4]]);
        q("INSERT INTO quizzes (question, options, correct_answer, points) VALUES (?, ?, ?, ?)",
          [$parts[0], $opts, $correct, (float)$parts[6]]);
        q("UPDATE users SET state = NULL WHERE id = ?", [$user['id']]);
        send($chatId, "✅ Quiz added!\n❓ {$parts[0]}\n✅ Answer: $correct\n💰 {$parts[6]} " . COIN_SYMBOL);
        quizManagement($chatId, $userId);
    }
    else { q("UPDATE users SET state = NULL WHERE id = ?", [$user['id']]); send($chatId, "❓ Cancelled."); }
}

// ==================== ADMIN PANEL ====================
function mainMenuKeyboard($userId) {
    if ($userId == ADMIN_ID) return ['keyboard' => [
        [['text' => '🔐 Admin Panel']],
        [['text' => '💰 Balance'], ['text' => '🔗 Referral']],
    ], 'resize_keyboard' => true];
    return ['keyboard' => [
        [['text' => '💰 Balance'], ['text' => '🔗 Referral']],
    ], 'resize_keyboard' => true];
}
function adminPanel($chatId, $userId) {
    send($chatId, "🔐 <b>Admin Panel</b>\n\nSelect:", ['keyboard' => [
        [['text' => '⚙️ FaucetPay Settings']],
        [['text' => '📢 Channel Settings']],
        [['text' => '🎯 Task Management'], ['text' => '📝 Quiz Management']],
        [['text' => '📊 Bot Stats'], ['text' => '👥 Users']],
        [['text' => '💰 Pending Withdrawals']],
        [['text' => '🐦 Pending Twitter Tasks']],
        [['text' => '⬅️ Main Menu']],
    ], 'resize_keyboard' => true]);
}
function faucetPaySettings($chatId, $userId) {
    $key = getSetting('faucetpay_api_key');
    $cur = getSetting('faucetpay_currency', 'USDT');
    $msg = "⚙️ <b>FaucetPay Settings</b>\n\n";
    $msg .= "🔑 API Key: " . ($key ? substr($key,0,8).'****' : '❌ Not set') . "\n";
    $msg .= "💱 Currency: <b>$cur</b>\n";
    $msg .= "💰 Claim: <b>" . getSetting('claim_amount') . "</b> $cur\n";
    $msg .= "⏱️ Cooldown: <b>" . (getSetting('claim_cooldown')/60) . " min</b>\n";
    $msg .= "📤 Min Withdraw: <b>" . getSetting('min_withdraw') . "</b>\n\n👇 Edit:";
    send($chatId, $msg, ['inline_keyboard' => [
        [['text' => '🔑 API Key', 'callback_data' => 'set_fp_key']],
        [['text' => '💱 Currency', 'callback_data' => 'set_fp_currency']],
        [['text' => '💰 Claim Amount', 'callback_data' => 'set_claim_amount']],
        [['text' => '⏱️ Cooldown', 'callback_data' => 'set_cooldown']],
        [['text' => '📤 Min Withdraw', 'callback_data' => 'set_min_withdraw']],
    ]]);
}

// ==================== CHANNEL SETTINGS ====================
function channelSettings($chatId, $userId) {
    $pay = getSetting('payment_channel', '');
    $task = getSetting('task_channel', '');
    $broadcast = getSetting('broadcast_on_task', '1') == '1' ? '🟢 ON' : '🔴 OFF';
    $annPay = getSetting('announce_payments', '1') == '1' ? '🟢 ON' : '🔴 OFF';
    $annTask = getSetting('announce_task_complete', '1') == '1' ? '🟢 ON' : '🔴 OFF';

    $msg = "📢 <b>Channel Settings</b>\n\n";
    $msg .= "━━━━━━━━━━━━━━━━━━━━━\n";
    $msg .= "💸 Payment Channel: " . ($pay ? "<code>$pay</code>" : "❌ Not set") . "\n";
    $msg .= "🎯 Task Channel: " . ($task ? "<code>$task</code>" : "❌ Not set") . "\n";
    $msg .= "━━━━━━━━━━━━━━━━━━━━━\n";
    $msg .= "🔔 Announce Payments: $annPay\n";
    $msg .= "🔔 Announce Task Complete: $annTask\n";
    $msg .= "🔔 Broadcast New Task: $broadcast\n";
    $msg .= "━━━━━━━━━━━━━━━━━━━━━\n\n";
    $msg .= "💡 <b>Channel Format:</b>\n";
    $msg .= "<code>@mychannel</code> or <code>-1001234567890</code>\n\n";
    $msg .= "⚠️ Bot কে channel এ <b>Admin</b> করতে হবে!";

    send($chatId, $msg, ['inline_keyboard' => [
        [['text' => '💸 Set Payment Channel', 'callback_data' => 'set_payment_ch']],
        [['text' => '🎯 Set Task Channel', 'callback_data' => 'set_task_ch']],
        [['text' => '🔔 Toggle Broadcast', 'callback_data' => 'toggle_broadcast']],
        [['text' => '🔔 Toggle Pay Announce', 'callback_data' => 'toggle_ann_pay']],
        [['text' => '🔔 Toggle Task Announce', 'callback_data' => 'toggle_ann_task']],
    ]]);
}

function quizManagement($chatId, $userId) {
    $total = q("SELECT COUNT(*) FROM quizzes WHERE is_active = 1")->fetchColumn();
    $attempts = q("SELECT COUNT(*) FROM user_quizzes")->fetchColumn();
    $correct = q("SELECT COUNT(*) FROM user_quizzes WHERE is_correct = 1")->fetchColumn();
    $msg = "📝 <b>Quiz Management</b>\n\n";
    $msg .= "📚 Active Quizzes: <b>$total</b>\n";
    $msg .= "🎯 Total Attempts: <b>$attempts</b>\n";
    $msg .= "✅ Correct Answers: <b>$correct</b>\n\n👇 Actions:";
    send($chatId, $msg, ['inline_keyboard' => [
        [['text' => '➕ Add Quiz', 'callback_data' => 'add_quiz']],
        [['text' => '📋 List Quizzes', 'callback_data' => 'list_quizzes']],
    ]]);
}
function listQuizzes($chatId) {
    $list = q("SELECT * FROM quizzes ORDER BY id DESC LIMIT 30")->fetchAll();
    if (empty($list)) { send($chatId, "No quizzes yet."); return; }
    $msg = "📋 <b>Quizzes</b>\n\n";
    $kb = ['inline_keyboard' => []];
    foreach ($list as $qz) {
        $s = $qz['is_active'] ? '🟢' : '🔴';
        $msg .= "$s #{$qz['id']} — " . htmlspecialchars(substr($qz['question'],0,50)) . "\n";
        $msg .= "   ✅ Answer: {$qz['correct_answer']} | 💰 {$qz['points']} " . COIN_SYMBOL . "\n\n";
        $kb['inline_keyboard'][] = [
            ['text' => ($qz['is_active'] ? '🔴 Disable' : '🟢 Enable') . " #{$qz['id']}", 'callback_data' => "qz_toggle_{$qz['id']}"],
            ['text' => "🗑️ Delete #{$qz['id']}", 'callback_data' => "qz_del_{$qz['id']}"],
        ];
    }
    send($chatId, $msg, $kb);
}

function taskManagement($chatId, $userId) {
    $tgCount = q("SELECT COUNT(*) FROM tasks WHERE is_active = 1")->fetchColumn();
    $twCount = q("SELECT COUNT(*) FROM twitter_tasks WHERE is_active = 1")->fetchColumn();
    $pendTw = q("SELECT COUNT(*) FROM user_twitter_tasks WHERE status = 'pending'")->fetchColumn();
    $msg = "🎯 <b>Task Management</b>\n\n";
    $msg .= "📱 Telegram Tasks: <b>$tgCount</b> active\n";
    $msg .= "🐦 Twitter Tasks: <b>$twCount</b> active\n";
    $msg .= "⏳ Pending Twitter: <b>$pendTw</b>\n\n👇 Actions:";
    send($chatId, $msg, ['inline_keyboard' => [
        [['text' => '➕ Add Telegram Task', 'callback_data' => 'add_tg_task']],
        [['text' => '➕ Add Twitter Task', 'callback_data' => 'add_tw_task']],
        [['text' => '📋 List Telegram Tasks', 'callback_data' => 'list_tg_tasks']],
        [['text' => '📋 List Twitter Tasks', 'callback_data' => 'list_tw_tasks']],
        [['text' => '🐦 Pending Twitter Subs', 'callback_data' => 'list_pending_tw']],
    ]]);
}
function listTgTasks($chatId) {
    $tasks = q("SELECT * FROM tasks ORDER BY id DESC LIMIT 30")->fetchAll();
    if (empty($tasks)) { send($chatId, "No Telegram tasks yet."); return; }
    $msg = "📋 <b>Telegram Tasks</b>\n\n";
    $kb = ['inline_keyboard' => []];
    foreach ($tasks as $t) {
        $s = $t['is_active'] ? '🟢' : '🔴';
        $msg .= "$s #{$t['id']} — " . htmlspecialchars($t['task_name']) . "\n";
        $msg .= "   💰 {$t['points']} " . COIN_SYMBOL . " | 📢 {$t['chat_username']}\n\n";
        $kb['inline_keyboard'][] = [
            ['text' => ($t['is_active'] ? '🔴 Disable' : '🟢 Enable') . " #{$t['id']}", 'callback_data' => "tg_toggle_{$t['id']}"],
            ['text' => "🗑️ Delete #{$t['id']}", 'callback_data' => "tg_del_{$t['id']}"],
        ];
    }
    send($chatId, $msg, $kb);
}
function listTwTasks($chatId) {
    $tasks = q("SELECT * FROM twitter_tasks ORDER BY id DESC LIMIT 30")->fetchAll();
    if (empty($tasks)) { send($chatId, "No Twitter tasks yet."); return; }
    $msg = "🐦 <b>Twitter Tasks</b>\n\n";
    $kb = ['inline_keyboard' => []];
    foreach ($tasks as $t) {
        $s = $t['is_active'] ? '🟢' : '🔴';
        $msg .= "$s #{$t['id']} — " . htmlspecialchars($t['task_name']) . "\n";
        $msg .= "   💰 {$t['points']} " . COIN_SYMBOL . " | 🏷️ {$t['task_type']}\n\n";
        $kb['inline_keyboard'][] = [
            ['text' => ($t['is_active'] ? '🔴 Disable' : '🟢 Enable') . " #{$t['id']}", 'callback_data' => "tw_toggle_{$t['id']}"],
            ['text' => "🗑️ Delete #{$t['id']}", 'callback_data' => "tw_del_{$t['id']}"],
        ];
    }
    send($chatId, $msg, $kb);
}
function pendingTwitterSubmissions($chatId, $userId) {
    $list = q("SELECT ut.*, u.first_name, u.username, u.chat_id, tt.task_name, tt.points, tt.twitter_url
               FROM user_twitter_tasks ut
               JOIN users u ON ut.user_id = u.id
               JOIN twitter_tasks tt ON ut.twitter_task_id = tt.id
               WHERE ut.status = 'pending' ORDER BY ut.id ASC LIMIT 20")->fetchAll();
    if (empty($list)) { send($chatId, "✅ No pending submissions."); return; }
    foreach ($list as $s) {
        send($chatId, "Submission #{$s['id']} — " . htmlspecialchars($s['task_name']) . "\n👤 @" . htmlspecialchars($s['twitter_username'] ?: 'N/A') . "\n💰 {$s['points']} " . COIN_SYMBOL, ['inline_keyboard' => [[
            ['text' => '✅ Approve', 'callback_data' => "tw_approve_{$s['id']}"],
            ['text' => '❌ Reject', 'callback_data' => "tw_reject_{$s['id']}"],
        ]]]);
    }
}

function botStats($chatId, $userId) {
    $u = q("SELECT COUNT(*) FROM users")->fetchColumn();
    $c = q("SELECT COUNT(*) FROM claims")->fetchColumn();
    $tc = q("SELECT SUM(amount) FROM claims")->fetchColumn() ?: 0;
    $tw = q("SELECT SUM(amount) FROM withdrawals WHERE status = 'completed'")->fetchColumn() ?: 0;
    $p = q("SELECT COUNT(*) FROM withdrawals WHERE status = 'pending'")->fetchColumn();
    $ttc = q("SELECT COUNT(*) FROM user_tasks")->fetchColumn();
    $twc = q("SELECT COUNT(*) FROM user_twitter_tasks WHERE status = 'approved'")->fetchColumn();
    $qzc = q("SELECT COUNT(*) FROM user_quizzes WHERE is_correct = 1")->fetchColumn();
    $msg = "📊 <b>Bot Statistics</b>\n\n";
    $msg .= "👥 Users: <b>" . number_format($u) . "</b>\n";
    $msg .= "🎯 Claims: <b>" . number_format($c) . "</b> (" . fmt($tc) . " " . COIN_SYMBOL . ")\n";
    $msg .= "📤 Withdrawn: <b>" . fmt($tw) . "</b>\n";
    $msg .= "⏳ Pending WD: <b>$p</b>\n";
    $msg .= "✅ TG Tasks done: <b>$ttc</b>\n";
    $msg .= "✅ TW Tasks done: <b>$twc</b>\n";
    $msg .= "📝 Correct Quizzes: <b>$qzc</b>";
    send($chatId, $msg);
}
function listUsers($chatId, $userId) {
    $list = q("SELECT id, first_name, username, balance FROM users ORDER BY id DESC LIMIT 20")->fetchAll();
    $msg = "👥 <b>Recent Users</b>\n\n";
    foreach ($list as $u) {
        $msg .= "🆔 #{$u['id']} — " . htmlspecialchars($u['first_name']);
        if ($u['username']) $msg .= " (@" . $u['username'] . ")";
        $msg .= " — " . fmt($u['balance']) . " " . COIN_SYMBOL . "\n";
    }
    send($chatId, $msg);
}
function pendingWithdrawals($chatId, $userId) {
    $list = q("SELECT w.*, u.first_name, u.username FROM withdrawals w JOIN users u ON w.user_id = u.id WHERE w.status = 'pending' ORDER BY w.id ASC LIMIT 20")->fetchAll();
    if (empty($list)) { send($chatId, "✅ No pending withdrawals."); return; }
    foreach ($list as $w) {
        $u = htmlspecialchars($w['first_name']) . ($w['username'] ? " (@" . $w['username'] . ")" : '');
        send($chatId, "💰 #{$w['id']} — $u\n💵 " . fmt($w['amount']) . " " . COIN_SYMBOL . "\n📧 {$w['faucetpay_email']}", ['inline_keyboard' => [[
            ['text' => '✅ Approve', 'callback_data' => "approve_w_{$w['id']}"],
            ['text' => '❌ Reject', 'callback_data' => "reject_w_{$w['id']}"],
        ]]]);
    }
}

// ==================== CALLBACK HANDLER ====================
function handleCallback($cb) {
    $chatId = $cb['message']['chat']['id'];
    $msgId = $cb['message']['message_id'];
    $userId = $cb['from']['id'];
    $data = $cb['data'];
    $user = getUserByChat($chatId);
    if (!$user) { tg('answerCallbackQuery', ['callback_query_id' => $cb['id']]); return; }

    if ($data == 'bal')
        tg('answerCallbackQuery', ['callback_query_id' => $cb['id'], 'text' => "Balance: " . fmt($user['balance']) . " " . COIN_SYMBOL, 'show_alert' => true]);
    elseif ($data == 'ref')
        tg('answerCallbackQuery', ['callback_query_id' => $cb['id'], 'text' => "https://t.me/" . BOT_USERNAME . "?start=" . $user['referral_code'], 'show_alert' => true]);
    elseif ($userId == ADMIN_ID) {
        if ($data == 'set_fp_key') { q("UPDATE users SET state='edit_fp_key' WHERE id=?", [$user['id']]); tg('answerCallbackQuery',['callback_query_id'=>$cb['id']]); send($chatId, "🔑 Send new API Key (or /cancel):"); }
        elseif ($data == 'set_fp_currency') { q("UPDATE users SET state='edit_fp_currency' WHERE id=?", [$user['id']]); tg('answerCallbackQuery',['callback_query_id'=>$cb['id']]); send($chatId, "💱 Send: USDT, BTC, DOGE, LTC, ETH, TRX"); }
        elseif ($data == 'set_claim_amount') { q("UPDATE users SET state='edit_claim_amount' WHERE id=?", [$user['id']]); tg('answerCallbackQuery',['callback_query_id'=>$cb['id']]); send($chatId, "💰 Send claim amount (e.g., 0.01)"); }
        elseif ($data == 'set_cooldown') { q("UPDATE users SET state='edit_cooldown' WHERE id=?", [$user['id']]); tg('answerCallbackQuery',['callback_query_id'=>$cb['id']]); send($chatId, "⏱️ Send cooldown in seconds (min 60)"); }
        elseif ($data == 'set_min_withdraw') { q("UPDATE users SET state='edit_min_withdraw' WHERE id=?", [$user['id']]); tg('answerCallbackQuery',['callback_query_id'=>$cb['id']]); send($chatId, "📤 Send min withdraw (e.g., 0.5)"); }
        // Channel settings
        elseif ($data == 'set_payment_ch') {
            q("UPDATE users SET state='edit_payment_channel' WHERE id=?", [$user['id']]);
            tg('answerCallbackQuery',['callback_query_id'=>$cb['id']]);
            send($chatId, "💸 <b>Set Payment Channel</b>\n\nChannel username পাঠান:\n<code>@mychannel</code> or <code>-1001234567890</code>\n\n⚠️ Bot কে channel এ admin করতে হবে!\n\nSend <code>0</code> to disable\n/cancel to abort");
        }
        elseif ($data == 'set_task_ch') {
            q("UPDATE users SET state='edit_task_channel' WHERE id=?", [$user['id']]);
            tg('answerCallbackQuery',['callback_query_id'=>$cb['id']]);
            send($chatId, "🎯 <b>Set Task Channel</b>\n\nChannel username পাঠান:\n<code>@mychannel</code> or <code>-1001234567890</code>\n\n⚠️ Bot কে channel এ admin করতে হবে!\n\nSend <code>0</code> to disable\n/cancel to abort");
        }
        elseif ($data == 'toggle_broadcast') {
            $cur = getSetting('broadcast_on_task', '1');
            updateSetting('broadcast_on_task', $cur == '1' ? '0' : '1');
            tg('answerCallbackQuery',['callback_query_id'=>$cb['id'],'text'=>'Toggled']);
            channelSettings($chatId, $userId);
        }
        elseif ($data == 'toggle_ann_pay') {
            $cur = getSetting('announce_payments', '1');
            updateSetting('announce_payments', $cur == '1' ? '0' : '1');
            tg('answerCallbackQuery',['callback_query_id'=>$cb['id'],'text'=>'Toggled']);
            channelSettings($chatId, $userId);
        }
        elseif ($data == 'toggle_ann_task') {
            $cur = getSetting('announce_task_complete', '1');
            updateSetting('announce_task_complete', $cur == '1' ? '0' : '1');
            tg('answerCallbackQuery',['callback_query_id'=>$cb['id'],'text'=>'Toggled']);
            channelSettings($chatId, $userId);
        }
        elseif ($data == 'add_tg_task') { q("UPDATE users SET state='add_tg_task' WHERE id=?", [$user['id']]); tg('answerCallbackQuery',['callback_query_id'=>$cb['id']]); send($chatId, "📝 <b>Add Telegram Task</b>\n\nFormat:\n<code>Name | Description | @channel | Reward</code>\n\nExample:\n<code>Join Channel | Join our channel | @mychannel | 0.05</code>\n\n⚠️ Task যোগ করলে সব user notification পাবে!"); }
        elseif ($data == 'add_tw_task') { q("UPDATE users SET state='add_tw_task' WHERE id=?", [$user['id']]); tg('answerCallbackQuery',['callback_query_id'=>$cb['id']]); send($chatId, "🐦 <b>Add Twitter Task</b>\n\nFormat:\n<code>Name | Description | URL | Type | Reward</code>\n\nExample:\n<code>Follow Us | Follow our Twitter | https://x.com/example | follow | 0.05</code>\n\n⚠️ Task যোগ করলে সব user notification পাবে!"); }
        elseif ($data == 'add_quiz') { q("UPDATE users SET state='add_quiz' WHERE id=?", [$user['id']]); tg('answerCallbackQuery',['callback_query_id'=>$cb['id']]); send($chatId, "📝 <b>Add Quiz</b>\n\nFormat:\n<code>Question | A | B | C | D | Correct(A/B/C/D) | Reward</code>\n\nExample:\n<code>What is 2+2? | 3 | 4 | 5 | 6 | B | 0.005</code>"); }
        elseif ($data == 'list_tg_tasks') { listTgTasks($chatId); tg('answerCallbackQuery',['callback_query_id'=>$cb['id']]); }
        elseif ($data == 'list_tw_tasks') { listTwTasks($chatId); tg('answerCallbackQuery',['callback_query_id'=>$cb['id']]); }
        elseif ($data == 'list_pending_tw') { pendingTwitterSubmissions($chatId, $userId); tg('answerCallbackQuery',['callback_query_id'=>$cb['id']]); }
        elseif ($data == 'list_quizzes') { listQuizzes($chatId); tg('answerCallbackQuery',['callback_query_id'=>$cb['id']]); }
        elseif (strpos($data, 'tg_toggle_') === 0) { q("UPDATE tasks SET is_active = NOT is_active WHERE id = ?", [(int)str_replace('tg_toggle_', '', $data)]); tg('answerCallbackQuery', ['callback_query_id' => $cb['id'], 'text' => 'Toggled']); listTgTasks($chatId); }
        elseif (strpos($data, 'tg_del_') === 0) { q("DELETE FROM tasks WHERE id = ?", [(int)str_replace('tg_del_', '', $data)]); tg('answerCallbackQuery', ['callback_query_id' => $cb['id'], 'text' => 'Deleted']); listTgTasks($chatId); }
        elseif (strpos($data, 'tw_toggle_') === 0) { q("UPDATE twitter_tasks SET is_active = NOT is_active WHERE id = ?", [(int)str_replace('tw_toggle_', '', $data)]); tg('answerCallbackQuery', ['callback_query_id' => $cb['id'], 'text' => 'Toggled']); listTwTasks($chatId); }
        elseif (strpos($data, 'tw_del_') === 0) { q("DELETE FROM twitter_tasks WHERE id = ?", [(int)str_replace('tw_del_', '', $data)]); tg('answerCallbackQuery', ['callback_query_id' => $cb['id'], 'text' => 'Deleted']); listTwTasks($chatId); }
        elseif (strpos($data, 'qz_toggle_') === 0) { q("UPDATE quizzes SET is_active = NOT is_active WHERE id = ?", [(int)str_replace('qz_toggle_', '', $data)]); tg('answerCallbackQuery', ['callback_query_id' => $cb['id'], 'text' => 'Toggled']); listQuizzes($chatId); }
        elseif (strpos($data, 'qz_del_') === 0) { q("DELETE FROM quizzes WHERE id = ?", [(int)str_replace('qz_del_', '', $data)]); tg('answerCallbackQuery', ['callback_query_id' => $cb['id'], 'text' => 'Deleted']); listQuizzes($chatId); }
        elseif (strpos($data, 'tw_approve_') === 0) {
            $id = (int)str_replace('tw_approve_', '', $data);
            $s = q("SELECT ut.*, tt.points, tt.task_name FROM user_twitter_tasks ut JOIN twitter_tasks tt ON ut.twitter_task_id = tt.id WHERE ut.id = ? AND ut.status = 'pending'", [$id])->fetch();
            if ($s) {
                q("UPDATE user_twitter_tasks SET status='approved', reviewed_at=NOW() WHERE id=?", [$id]);
                q("UPDATE users SET balance = balance + ?, total_task_earned = total_task_earned + ? WHERE id = ?", [$s['points'], $s['points'], $s['user_id']]);
                $u = getUserById($s['user_id']);
                if ($u) {
                    send($u['chat_id'], "✅ Twitter task approved! +{$s['points']} " . COIN_SYMBOL);
                    addNotification($s['user_id'], '✅ Twitter Task Approved', "+{$s['points']} " . COIN_SYMBOL, 'success');
                    announceTaskComplete($u, $s['task_name'], $s['points'], 'twitter');
                }
                tg('answerCallbackQuery', ['callback_query_id' => $cb['id'], 'text' => 'Approved +' . $s['points']]);
            } else tg('answerCallbackQuery', ['callback_query_id' => $cb['id'], 'text' => 'Not found']);
        }
        elseif (strpos($data, 'tw_reject_') === 0) {
            $id = (int)str_replace('tw_reject_', '', $data);
            q("UPDATE user_twitter_tasks SET status='rejected', reviewed_at=NOW() WHERE id=?", [$id]);
            $s = q("SELECT user_id FROM user_twitter_tasks WHERE id = ?", [$id])->fetch();
            if ($s) { $u = getUserById($s['user_id']); if ($u) send($u['chat_id'], "❌ Twitter task rejected."); addNotification($s['user_id'], '❌ Twitter Task Rejected', 'Your submission was rejected.', 'error'); }
            tg('answerCallbackQuery', ['callback_query_id' => $cb['id'], 'text' => 'Rejected']);
        }
        elseif (strpos($data, 'approve_w_') === 0) {
            $wid = (int)str_replace('approve_w_', '', $data);
            tg('answerCallbackQuery', ['callback_query_id' => $cb['id'], 'text' => 'Processing...']);
            processWithdrawal($wid, true);
            editMessage($chatId, $msgId, "✅ Withdrawal #$wid processed.");
        }
        elseif (strpos($data, 'reject_w_') === 0) {
            $wid = (int)str_replace('reject_w_', '', $data);
            rejectWithdrawal($wid, 'Rejected by admin');
            tg('answerCallbackQuery', ['callback_query_id' => $cb['id'], 'text' => 'Rejected']);
            editMessage($chatId, $msgId, "❌ Withdrawal #$wid rejected.");
        }
    }
    else tg('answerCallbackQuery', ['callback_query_id' => $cb['id']]);
}

// ==================== MINI APP API ====================
function api() {
    header('Content-Type: application/json');
    $action = $_REQUEST['action'] ?? '';
    $initData = $_POST['initData'] ?? $_GET['initData'] ?? '';
    $tgUser = validateWebAppData($initData);
    if (!$tgUser) { echo json_encode(['ok' => false, 'err' => 'Auth failed']); return; }

    $user = ensureUser($tgUser);
    if ($user['is_banned']) { echo json_encode(['ok' => false, 'err' => 'Banned']); return; }

    $claimAmount = (float)getSetting('claim_amount', '0.01');
    $cooldown = (int)getSetting('claim_cooldown', '3600');
    $minWithdraw = (float)getSetting('min_withdraw', '0.5');
    $currency = getSetting('faucetpay_currency', 'USDT');

    switch ($action) {
        case 'me':
            $next = 0;
            if ($user['last_claim']) $next = max(0, strtotime($user['last_claim']) + $cooldown - time());
            $unread = q("SELECT COUNT(*) FROM notifications WHERE user_id = ? AND is_read = 0", [$user['id']])->fetchColumn();
            $today = date('Y-m-d');
            $bonusClaimable = ($user['last_bonus'] !== $today);
            echo json_encode(['ok' => true, 'user' => [
                'id' => (int)$user['id'], 'first_name' => $user['first_name'],
                'balance' => (float)$user['balance'],
                'total_claimed' => (float)$user['total_claimed'],
                'total_withdrawn' => (float)$user['total_withdrawn'],
                'total_task_earned' => (float)$user['total_task_earned'],
                'total_bonus_earned' => (float)$user['total_bonus_earned'],
                'total_quiz_earned' => (float)$user['total_quiz_earned'],
                'faucetpay_email' => $user['faucetpay_email'],
                'twitter_username' => $user['twitter_username'],
                'referral_code' => $user['referral_code'],
                'claims' => (int)$user['claims_count'],
                'next_claim_in' => $next,
                'bonus_streak' => (int)$user['bonus_streak'],
                'bonus_claimable' => $bonusClaimable,
                'unread_notifications' => (int)$unread,
            ], 'config' => [
                'coin' => $currency, 'claim_amount' => $claimAmount,
                'cooldown' => $cooldown, 'min_withdraw' => $minWithdraw,
            ]]);
            break;

        case 'claim':
            $last = $user['last_claim'] ? strtotime($user['last_claim']) : 0;
            if (time() - $last < $cooldown) { echo json_encode(['ok' => false, 'err' => 'Cooldown', 'wait' => $cooldown - (time()-$last)]); return; }
            db()->beginTransaction();
            try {
                q("UPDATE users SET balance=balance+?, total_claimed=total_claimed+?, claims_count=claims_count+1, last_claim=NOW() WHERE id=?",
                  [$claimAmount, $claimAmount, $user['id']]);
                q("INSERT INTO claims (user_id, amount, ip) VALUES (?, ?, ?)",
                  [$user['id'], $claimAmount, $_SERVER['REMOTE_ADDR'] ?? '']);
                db()->commit();
                echo json_encode(['ok' => true, 'amount' => $claimAmount, 'new_balance' => (float)$user['balance']+$claimAmount, 'next_claim_in' => $cooldown]);
            } catch (Exception $e) { db()->rollBack(); echo json_encode(['ok' => false, 'err' => 'DB error']); }
            break;

        case 'daily_bonus':
            if (getSetting('daily_bonus_enabled', '1') != '1') { echo json_encode(['ok'=>false,'err'=>'Disabled']); return; }
            $today = date('Y-m-d');
            $yesterday = date('Y-m-d', strtotime('-1 day'));
            if ($user['last_bonus'] === $today) { echo json_encode(['ok' => false, 'err' => 'Already claimed today']); return; }
            $streak = 1;
            if ($user['last_bonus'] === $yesterday && $user['bonus_streak'] > 0) {
                $streak = $user['bonus_streak'] + 1;
                if ($streak > 7) $streak = 1;
            }
            $rewards = [1=>0.005, 2=>0.006, 3=>0.008, 4=>0.010, 5=>0.015, 6=>0.020, 7=>0.030];
            $reward = $rewards[$streak] ?? 0.005;
            db()->beginTransaction();
            try {
                q("UPDATE users SET balance=balance+?, total_bonus_earned=total_bonus_earned+?, bonus_streak=?, last_bonus=? WHERE id=?",
                  [$reward, $reward, $streak, $today, $user['id']]);
                db()->commit();
                addNotification($user['id'], '🔥 Daily Bonus!', "+{$reward} " . COIN_SYMBOL . " (Day {$streak})", 'success');
                send($user['chat_id'], "🔥 <b>Daily Bonus!</b>\n\n💰 +{$reward} " . COIN_SYMBOL . "\n🎯 Day {$streak} streak!");
                echo json_encode(['ok' => true, 'amount' => $reward, 'streak' => $streak, 'new_balance' => (float)$user['balance'] + $reward]);
            } catch (Exception $e) { db()->rollBack(); echo json_encode(['ok' => false, 'err' => 'DB error']); }
            break;

        case 'quizzes_list':
            $quizzes = q("SELECT * FROM quizzes WHERE is_active = 1 ORDER BY id ASC LIMIT 50")->fetchAll();
            $attempts = q("SELECT quiz_id, is_correct, answer FROM user_quizzes WHERE user_id = ?", [$user['id']])->fetchAll();
            $statusMap = [];
            foreach ($attempts as $a) $statusMap[$a['quiz_id']] = $a;
            $list = array_map(function($qz) use ($statusMap) {
                $opts = json_decode($qz['options'], true);
                $att = $statusMap[$qz['id']] ?? null;
                return ['id' => (int)$qz['id'], 'question' => $qz['question'], 'options' => $opts,
                        'points' => (float)$qz['points'], 'attempted' => $att ? true : false,
                        'answered' => $att['answer'] ?? null, 'is_correct' => $att ? (bool)$att['is_correct'] : null,
                        'correct_answer' => $att ? $qz['correct_answer'] : null];
            }, $quizzes);
            echo json_encode(['ok' => true, 'quizzes' => $list]);
            break;

        case 'submit_quiz':
            $qid = (int)($_POST['quiz_id'] ?? 0);
            $ans = strtoupper(trim($_POST['answer'] ?? ''));
            if (!in_array($ans, ['A','B','C','D'])) { echo json_encode(['ok'=>false,'err'=>'Invalid answer']); return; }
            $qz = q("SELECT * FROM quizzes WHERE id = ? AND is_active = 1", [$qid])->fetch();
            if (!$qz) { echo json_encode(['ok'=>false,'err'=>'Quiz not found']); return; }
            if (q("SELECT id FROM user_quizzes WHERE user_id=? AND quiz_id=?", [$user['id'], $qid])->fetch()) {
                echo json_encode(['ok'=>false,'err'=>'Already attempted']); return;
            }
            $correct = ($ans === $qz['correct_answer']);
            $points = $correct ? (float)$qz['points'] : 0;
            db()->beginTransaction();
            try {
                q("INSERT INTO user_quizzes (user_id, quiz_id, answer, is_correct, points_earned) VALUES (?,?,?,?,?)",
                  [$user['id'], $qid, $ans, $correct?1:0, $points]);
                if ($correct) q("UPDATE users SET balance=balance+?, total_quiz_earned=total_quiz_earned+? WHERE id=?",
                                [$points, $points, $user['id']]);
                db()->commit();
                if ($correct) {
                    addNotification($user['id'], '📝 Quiz Correct!', "+{$points} " . COIN_SYMBOL, 'success');
                    send($user['chat_id'], "🎉 Quiz correct! +{$points} " . COIN_SYMBOL);
                } else {
                    addNotification($user['id'], '❌ Quiz Wrong', "Correct: {$qz['correct_answer']}", 'error');
                }
                echo json_encode(['ok' => true, 'correct' => $correct, 'points' => $points,
                                  'correct_answer' => $qz['correct_answer'],
                                  'new_balance' => (float)$user['balance'] + $points]);
            } catch (Exception $e) { db()->rollBack(); echo json_encode(['ok'=>false,'err'=>'DB error']); }
            break;

        case 'leaderboard':
            if (getSetting('leaderboard_enabled', '1') != '1') { echo json_encode(['ok'=>false,'err'=>'Disabled']); return; }
            $top = q("SELECT id, first_name, username,
                      (total_claimed + total_task_earned + total_bonus_earned + total_quiz_earned) as total_earn
                      FROM users WHERE is_banned = 0
                      ORDER BY total_earn DESC LIMIT 10")->fetchAll();
            $myRank = q("SELECT COUNT(*) + 1 FROM users WHERE is_banned = 0 AND (total_claimed + total_task_earned + total_bonus_earned + total_quiz_earned) > 
                        (SELECT (total_claimed + total_task_earned + total_bonus_earned + total_quiz_earned) FROM users WHERE id = ?)",
                        [$user['id']])->fetchColumn();
            echo json_encode(['ok' => true, 'top' => array_map(function($t) {
                return ['id' => (int)$t['id'], 'name' => $t['first_name'] ?: 'User',
                        'username' => $t['username'], 'total' => (float)$t['total_earn']];
            }, $top), 'my_rank' => (int)$myRank]);
            break;

        case 'notifications':
            $list = q("SELECT * FROM notifications WHERE user_id = ? ORDER BY id DESC LIMIT 30", [$user['id']])->fetchAll();
            q("UPDATE notifications SET is_read = 1 WHERE user_id = ? AND is_read = 0", [$user['id']]);
            echo json_encode(['ok' => true, 'list' => array_map(function($n) {
                return ['id'=>(int)$n['id'],'title'=>$n['title'],'message'=>$n['message'],
                        'type'=>$n['type'],'is_read'=>(bool)$n['is_read'],'created_at'=>$n['created_at']];
            }, $list)]);
            break;

        case 'clear_notifications':
            q("DELETE FROM notifications WHERE user_id = ?", [$user['id']]);
            echo json_encode(['ok' => true]);
            break;

        case 'set_email':
            $e = trim($_POST['email'] ?? '');
            if (!filter_var($e, FILTER_VALIDATE_EMAIL)) { echo json_encode(['ok' => false, 'err' => 'Invalid email']); return; }
            $exists = q("SELECT id FROM users WHERE faucetpay_email = ? AND id != ?", [$e, $user['id']])->fetch();
            if ($exists) { echo json_encode(['ok' => false, 'err' => 'Already linked']); return; }
            $had = !empty($user['faucetpay_email']);
            q("UPDATE users SET faucetpay_email = ? WHERE id = ?", [$e, $user['id']]);
            if (!$had && $user['referred_by']) {
                $rb = (float)getSetting('referral_bonus', '0.005');
                if ($rb > 0) {
                    q("UPDATE users SET balance = balance + ? WHERE id = ?", [$rb, $user['referred_by']]);
                    $ru = getUserById($user['referred_by']);
                    if ($ru) {
                        send($ru['chat_id'], "🎉 Referral bonus +$rb $currency");
                        addNotification($ru['id'], '🎉 Referral Bonus', "+{$rb} {$currency}", 'success');
                    }
                }
            }
            echo json_encode(['ok' => true]);
            break;

        case 'withdraw':
            $amt = (float)($_POST['amount'] ?? 0);
            if ($amt < $minWithdraw) { echo json_encode(['ok' => false, 'err' => 'Min ' . $minWithdraw]); return; }
            if ($amt > $user['balance']) { echo json_encode(['ok' => false, 'err' => 'Insufficient']); return; }
            if (empty($user['faucetpay_email'])) { echo json_encode(['ok' => false, 'err' => 'Set FaucetPay email first']); return; }
            db()->beginTransaction();
            $s = q("UPDATE users SET balance=balance-? WHERE id=? AND balance>=?", [$amt, $user['id'], $amt]);
            if ($s->rowCount() == 0) { db()->rollBack(); echo json_encode(['ok' => false, 'err' => 'Insufficient']); return; }
            q("INSERT INTO withdrawals (user_id, amount, faucetpay_email, status, idempotency_key) VALUES (?, ?, ?, 'pending', ?)",
              [$user['id'], $amt, $user['faucetpay_email'], 'wd_' . bin2hex(random_bytes(10))]);
            $wid = db()->lastInsertId();
            db()->commit();
            $res = faucetPaySend($user['faucetpay_email'], $amt, $currency);
            if ($res['ok']) {
                q("UPDATE withdrawals SET status='completed', tx_id=?, processed_at=NOW() WHERE id=?", [$res['tx_id'], $wid]);
                q("UPDATE users SET total_withdrawn=total_withdrawn+? WHERE id=?", [$amt, $user['id']]);
                send($user['chat_id'], "✅ <b>Withdrawal Sent!</b>\n\n💵 Amount: {$amt} {$currency}\n📧 To: {$user['faucetpay_email']}\n🆔 TX: <code>{$res['tx_id']}</code>\n\nThank you! 🎉");
                addNotification($user['id'], '✅ Withdrawal Sent', "{$amt} {$currency} sent. TX: {$res['tx_id']}", 'success');
                // ============ AUTO POST TO PAYMENT CHANNEL ============
                announcePayment($user, $amt, $res['tx_id'], $user['faucetpay_email']);
                echo json_encode(['ok' => true, 'tx' => $res['tx_id']]);
            } else {
                q("UPDATE withdrawals SET error=? WHERE id=?", [$res['error'], $wid]);
                send(ADMIN_ID, "⚠️ Auto payout failed\n👤 #{$user['id']}\n💰 $amt $currency\n❌ {$res['error']}");
                addNotification($user['id'], '⏳ Withdrawal Pending', 'Auto payout failed. Admin will process soon.', 'warning');
                send($user['chat_id'], "⏳ <b>Withdrawal Pending</b>\n\n💵 {$amt} {$currency}\n\n⚠️ Auto payment failed. Admin has been notified and will process manually.\n\nYou'll get a message once completed.");
                echo json_encode(['ok' => false, 'err' => 'Failed. Moved to pending.', 'pending' => true]);
            }
            break;

        case 'tasks_list':
            $tg = q("SELECT * FROM tasks WHERE is_active = 1 ORDER BY id ASC")->fetchAll();
            $tw = q("SELECT * FROM twitter_tasks WHERE is_active = 1 ORDER BY id ASC")->fetchAll();
            $tgDone = q("SELECT task_id FROM user_tasks WHERE user_id = ?", [$user['id']])->fetchAll(PDO::FETCH_COLUMN);
            $twDone = q("SELECT twitter_task_id, status FROM user_twitter_tasks WHERE user_id = ?", [$user['id']])->fetchAll();
            $twStatus = [];
            foreach ($twDone as $r) $twStatus[$r['twitter_task_id']] = $r['status'];
            echo json_encode([
                'ok' => true,
                'telegram_tasks' => array_map(function($t) use ($tgDone) {
                    return ['id' => (int)$t['id'], 'name' => $t['task_name'], 'desc' => $t['task_description'],
                            'chat' => $t['chat_username'], 'points' => (float)$t['points'],
                            'done' => in_array($t['id'], $tgDone)];
                }, $tg),
                'twitter_tasks' => array_map(function($t) use ($twStatus) {
                    return ['id' => (int)$t['id'], 'name' => $t['task_name'], 'desc' => $t['task_description'],
                            'url' => $t['twitter_url'], 'type' => $t['task_type'], 'points' => (float)$t['points'],
                            'status' => $twStatus[$t['id']] ?? null];
                }, $tw),
                'twitter_username' => $user['twitter_username'],
            ]);
            break;

        case 'complete_tg_task':
            $tid = (int)($_POST['task_id'] ?? 0);
            $t = q("SELECT * FROM tasks WHERE id = ? AND is_active = 1", [$tid])->fetch();
            if (!$t) { echo json_encode(['ok' => false, 'err' => 'Task not found']); return; }
            if (q("SELECT id FROM user_tasks WHERE user_id = ? AND task_id = ?", [$user['id'], $tid])->fetch()) {
                echo json_encode(['ok' => false, 'err' => 'Already done']); return;
            }
            usleep(500000);
            $joined = isUserInChat($user['chat_id'], $t['chat_username']);
            if (!$joined) { usleep(1000000); $joined = isUserInChat($user['chat_id'], $t['chat_username']); }
            if (!$joined) {
                echo json_encode(['ok' => false, 'err' => 'Join ' . $t['chat_username'] . ' first!', 'need_join' => $t['chat_username']]);
                return;
            }
            db()->beginTransaction();
            try {
                q("INSERT INTO user_tasks (user_id, task_id, points_earned) VALUES (?, ?, ?)", [$user['id'], $tid, $t['points']]);
                q("UPDATE users SET balance = balance + ?, total_task_earned = total_task_earned + ? WHERE id = ?",
                  [$t['points'], $t['points'], $user['id']]);
                db()->commit();
                addNotification($user['id'], '🎯 Task Done', "+{$t['points']} " . COIN_SYMBOL, 'success');
                send($user['chat_id'], "🎯 <b>Task Completed!</b>\n\n📌 {$t['task_name']}\n💰 +{$t['points']} " . COIN_SYMBOL);
                // ============ AUTO POST TO TASK CHANNEL ============
                announceTaskComplete($user, $t['task_name'], $t['points'], 'telegram');
                echo json_encode(['ok' => true, 'points' => (float)$t['points']]);
            } catch (Exception $e) { db()->rollBack(); echo json_encode(['ok' => false, 'err' => 'DB error']); }
            break;

        case 'set_twitter':
            $tw = trim($_POST['twitter'] ?? '', "@ \t\n\r\0\x0B");
            if (strlen($tw) < 2 || strlen($tw) > 15 || !preg_match('/^[A-Za-z0-9_]+$/', $tw)) {
                echo json_encode(['ok' => false, 'err' => 'Invalid Twitter username']); return;
            }
            if (!empty($user['twitter_username'])) { echo json_encode(['ok' => false, 'err' => 'Already locked']); return; }
            $exists = q("SELECT id FROM users WHERE twitter_username = ? AND id != ?", [$tw, $user['id']])->fetch();
            if ($exists) { echo json_encode(['ok' => false, 'err' => 'Already linked']); return; }
            q("UPDATE users SET twitter_username = ? WHERE id = ?", [$tw, $user['id']]);
            echo json_encode(['ok' => true]);
            break;

        case 'submit_twitter':
            $tid = (int)($_POST['task_id'] ?? 0);
            if (empty($user['twitter_username'])) { echo json_encode(['ok' => false, 'err' => 'Set Twitter first']); return; }
            $t = q("SELECT * FROM twitter_tasks WHERE id = ? AND is_active = 1", [$tid])->fetch();
            if (!$t) { echo json_encode(['ok' => false, 'err' => 'Task not found']); return; }
            if (q("SELECT id FROM user_twitter_tasks WHERE user_id = ? AND twitter_task_id = ?", [$user['id'], $tid])->fetch()) {
                echo json_encode(['ok' => false, 'err' => 'Already submitted']); return;
            }
            q("INSERT INTO user_twitter_tasks (user_id, twitter_task_id, twitter_username, status) VALUES (?, ?, ?, 'pending')",
              [$user['id'], $tid, '@' . $user['twitter_username']]);
            send(ADMIN_ID, "🐦 New Twitter submission\n👤 #{$user['id']} @{$user['twitter_username']}\n🎯 " . $t['task_name'] . "\n💰 {$t['points']} " . COIN_SYMBOL);
            echo json_encode(['ok' => true]);
            break;

        case 'history':
            $c = q("SELECT amount, created_at FROM claims WHERE user_id = ? ORDER BY id DESC LIMIT 20", [$user['id']])->fetchAll();
            $w = q("SELECT amount, status, tx_id, created_at FROM withdrawals WHERE user_id = ? ORDER BY id DESC LIMIT 20", [$user['id']])->fetchAll();
            echo json_encode(['ok' => true, 'claims' => $c, 'withdrawals' => $w]);
            break;

        default:
            echo json_encode(['ok' => false, 'err' => 'Unknown action']);
    }
}

// ==================== WITHDRAWAL PROCESS ====================
function processWithdrawal($wid, $manual = false) {
    $w = q("SELECT * FROM withdrawals WHERE id = ?", [$wid])->fetch();
    if (!$w) return false;
    $cur = getSetting('faucetpay_currency', 'USDT');
    $res = faucetPaySend($w['faucetpay_email'], $w['amount'], $cur);
    if ($res['ok']) {
        q("UPDATE withdrawals SET status='completed', tx_id=?, processed_at=NOW(), error=NULL WHERE id=?", [$res['tx_id'], $wid]);
        q("UPDATE users SET total_withdrawn=total_withdrawn+? WHERE id=?", [$w['amount'], $w['user_id']]);
        $u = getUserById($w['user_id']);
        if ($u) {
            send($u['chat_id'], "✅ <b>Withdrawal Approved!</b>\n\n💵 {$w['amount']} $cur\n🆔 TX: <code>{$res['tx_id']}</code>");
            addNotification($u['id'], '✅ Withdrawal Approved', "{$w['amount']} {$cur} sent", 'success');
            announcePayment($u, $w['amount'], $res['tx_id'], $w['faucetpay_email']);
        }
        return true;
    } else {
        q("UPDATE withdrawals SET error=? WHERE id=?", [$res['error'], $wid]);
        if ($manual) send(ADMIN_ID, "❌ Retry failed: " . $res['error']);
        return false;
    }
}
function rejectWithdrawal($wid, $reason) {
    $w = q("SELECT * FROM withdrawals WHERE id = ? AND status IN ('pending','processing')", [$wid])->fetch();
    if (!$w) return false;
    db()->beginTransaction();
    try {
        q("UPDATE users SET balance = balance + ? WHERE id = ?", [$w['amount'], $w['user_id']]);
        q("UPDATE withdrawals SET status='rejected', error=?, processed_at=NOW() WHERE id=?", [$reason, $wid]);
        db()->commit();
        $u = getUserById($w['user_id']);
        if ($u) {
            send($u['chat_id'], "❌ Withdrawal rejected. Refunded: {$w['amount']} " . COIN_SYMBOL);
            addNotification($u['id'], '❌ Withdrawal Rejected', "Refunded {$w['amount']} " . COIN_SYMBOL, 'error');
        }
        return true;
    } catch (Exception $e) { db()->rollBack(); return false; }
}

// ==================== WORKER ====================
function worker() {
    header('Content-Type: text/plain');
    if (($_GET['key'] ?? '') !== hash('sha256', BOT_TOKEN . 'worker')) { echo "Unauthorized"; return; }
    $list = q("SELECT * FROM withdrawals WHERE status = 'pending' AND (error IS NULL OR error = '') ORDER BY id ASC LIMIT 10")->fetchAll();
    echo "Processing " . count($list) . "\n";
    foreach ($list as $w) {
        q("UPDATE withdrawals SET status='processing' WHERE id=? AND status='pending'", [$w['id']]);
        echo "WD #{$w['id']}: " . (processWithdrawal($w['id']) ? "OK" : "FAIL") . "\n";
        usleep(300000);
    }
    echo "Done.\n";
}

// ==================== DEBUG CHAT ====================
function debugChat() {
    header('Content-Type: text/plain');
    if (($_GET['admin'] ?? '') != ADMIN_ID) { echo "Unauthorized"; return; }
    $testUser = $_GET['user_id'] ?? '';
    $testChat = $_GET['chat'] ?? '';
    if (!$testUser || !$testChat) {
        echo "Usage: ?debug_chat=1&admin=" . ADMIN_ID . "&user_id=USER_ID&chat=@channel\n";
        return;
    }
    $chat = trim($testChat);
    if (strpos($chat, '@') !== 0 && strpos($chat, '-') !== 0 && !is_numeric($chat)) $chat = '@' . $chat;
    echo "Testing getChatMember:\nUser: $testUser\nChat: $chat\n\n";
    $r = tg('getChatMember', ['chat_id' => $chat, 'user_id' => $testUser]);
    echo json_encode($r, JSON_PRETTY_PRINT) . "\n\n";
    if (!empty($r['ok'])) {
        $status = strtolower($r['result']['status'] ?? '');
        echo "✅ Status: {$status}\nJoined: " . (in_array($status, ['creator','administrator','member','restricted']) ? 'YES' : 'NO');
    } else {
        echo "❌ Error: " . ($r['description'] ?? 'unknown');
    }
}

// ==================== MINI APP HTML ====================
function miniApp() {
    $coin = getSetting('faucetpay_currency', 'USDT');
    ?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
<title><?= $coin ?> Faucet</title>
<script src="https://telegram.org/js/telegram-web-app.js"></script>
<style>
*{margin:0;padding:0;box-sizing:border-box;-webkit-tap-highlight-color:transparent}
body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;background:linear-gradient(180deg,#0a0e27,#111827);color:#fff;min-height:100vh;padding-bottom:80px}
.page{padding:16px;display:none}.page.active{display:block}
.card{background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.1);border-radius:18px;padding:20px;margin-bottom:14px}
.balance{text-align:center;padding:30px 20px;background:linear-gradient(135deg,#26a17b,#1a7f5c);border-radius:22px;box-shadow:0 10px 40px rgba(38,161,123,.3)}
.balance .num{font-size:40px;font-weight:800;letter-spacing:-1px;margin:6px 0;font-variant-numeric:tabular-nums}
.balance .sub{opacity:.9;font-size:14px}
.btn{display:block;width:100%;padding:16px;border:none;border-radius:14px;font-size:16px;font-weight:700;cursor:pointer;transition:.2s;background:linear-gradient(135deg,#3b82f6,#8b5cf6);color:#fff;margin-top:10px}
.btn:active{transform:scale(.97)}
.btn:disabled{opacity:.55;cursor:not-allowed;background:#475569}
.btn-green{background:linear-gradient(135deg,#26a17b,#1a7f5c);box-shadow:0 4px 16px rgba(38,161,123,.4)}
.btn-orange{background:linear-gradient(135deg,#f59e0b,#ea580c);box-shadow:0 4px 16px rgba(245,158,11,.4)}
.btn-sm{padding:10px 14px;font-size:14px;width:auto;display:inline-block;margin:0}
.row{display:grid;grid-template-columns:1fr 1fr;gap:10px}
.stat{background:rgba(255,255,255,.05);border-radius:14px;padding:14px;text-align:center}
.stat .v{font-size:20px;font-weight:700;margin-bottom:4px}
.stat .l{font-size:12px;opacity:.7}
input{width:100%;padding:14px;border-radius:12px;border:1px solid rgba(255,255,255,.15);background:rgba(0,0,0,.3);color:#fff;font-size:15px;margin-top:8px;font-family:monospace}
input:focus{outline:none;border-color:#26a17b}
.title{font-size:18px;font-weight:700;margin-bottom:10px}
.muted{opacity:.6;font-size:13px;word-break:break-all}
.task{background:rgba(255,255,255,.05);border-radius:14px;padding:14px;margin-bottom:10px;border-left:3px solid #3b82f6}
.task.done{border-left-color:#26a17b;opacity:.65}
.task.pending{border-left-color:#f59e0b}
.task h4{font-size:15px;margin-bottom:6px}
.task .pts{color:#26a17b;font-weight:700;font-size:14px}
.task .desc{font-size:12px;opacity:.7;margin:6px 0}
.task-actions{display:flex;gap:8px;margin-top:10px;flex-wrap:wrap}
.opt{display:block;width:100%;padding:14px;border-radius:12px;border:2px solid rgba(255,255,255,.15);background:rgba(255,255,255,.04);color:#fff;font-size:15px;font-weight:600;cursor:pointer;margin-top:8px;text-align:left;transition:.2s}
.opt:hover,.opt:active{background:rgba(38,161,123,.15);border-color:#26a17b}
.opt.correct{background:rgba(38,161,123,.3);border-color:#26a17b}
.opt.wrong{background:rgba(239,68,68,.3);border-color:#ef4444}
.opt:disabled{cursor:not-allowed}
.streak{display:flex;gap:6px;justify-content:center;margin:10px 0;flex-wrap:wrap}
.day{width:38px;height:38px;border-radius:10px;background:rgba(255,255,255,.08);display:flex;align-items:center;justify-content:center;font-size:14px;font-weight:700;border:2px solid transparent}
.day.active{background:linear-gradient(135deg,#f59e0b,#ea580c);border-color:#fbbf24}
.day.done{background:#26a17b;border-color:#4ade80}
.lb-row{display:flex;align-items:center;padding:12px;border-radius:12px;background:rgba(255,255,255,.04);margin-bottom:8px;gap:12px}
.lb-row.me{background:rgba(38,161,123,.2);border:1px solid #26a17b}
.lb-rank{font-size:18px;font-weight:800;width:36px;text-align:center}
.lb-name{flex:1;font-weight:600}
.lb-amt{color:#26a17b;font-weight:700}
.notif{background:rgba(255,255,255,.05);border-radius:12px;padding:12px;margin-bottom:8px;border-left:3px solid #3b82f6}
.notif.success{border-left-color:#26a17b}
.notif.error{border-left-color:#ef4444}
.notif.warning{border-left-color:#f59e0b}
.notif h5{font-size:14px;margin-bottom:4px}
.notif p{font-size:12px;opacity:.75;margin-bottom:4px}
.notif small{font-size:11px;opacity:.5}
.nav{position:fixed;bottom:0;left:0;right:0;background:#0f172a;border-top:1px solid rgba(255,255,255,.1);display:grid;grid-template-columns:repeat(5,1fr);padding:8px 0;z-index:50}
.nav button{background:none;border:none;color:#94a3b8;font-size:10px;padding:6px 2px;cursor:pointer;font-weight:600;display:flex;flex-direction:column;align-items:center;gap:3px}
.nav button.active{color:#26a17b}
.nav button .icon{font-size:18px}
#toast{position:fixed;bottom:90px;left:20px;right:20px;padding:14px;border-radius:12px;background:#1e293b;border:1px solid #3b82f6;text-align:center;font-weight:600;transform:translateY(150px);transition:.3s;z-index:99;font-size:14px}
#toast.show{transform:translateY(0)}
.loader{display:inline-block;width:16px;height:16px;border:3px solid rgba(255,255,255,.3);border-top-color:#fff;border-radius:50%;animation:spin .7s linear infinite;vertical-align:middle}
@keyframes spin{to{transform:rotate(360deg)}}
.bell{position:fixed;top:16px;right:16px;background:rgba(15,23,42,.9);border:1px solid rgba(255,255,255,.15);border-radius:50%;width:42px;height:42px;display:flex;align-items:center;justify-content:center;font-size:18px;cursor:pointer;z-index:60}
.bell .badge{position:absolute;top:-2px;right:-2px;background:#ef4444;color:#fff;font-size:10px;font-weight:700;border-radius:10px;min-width:18px;height:18px;padding:0 5px;display:flex;align-items:center;justify-content:center}
</style>
</head>
<body>
<div class="bell" id="bell" onclick="openNotifications()">
  <span>🔔</span>
  <span class="badge" id="notifBadge" style="display:none">0</span>
</div>
<div id="page-faucet" class="page active"></div>
<div id="page-tasks" class="page"></div>
<div id="page-bonus" class="page"></div>
<div id="page-wallet" class="page"></div>
<div id="page-profile" class="page"></div>
<div class="nav">
  <button data-tab="faucet" class="active"><span class="icon">💵</span>Faucet</button>
  <button data-tab="tasks"><span class="icon">🎯</span>Tasks</button>
  <button data-tab="bonus"><span class="icon">🎁</span>Bonus</button>
  <button data-tab="wallet"><span class="icon">💸</span>Wallet</button>
  <button data-tab="profile"><span class="icon">👤</span>Me</button>
</div>
<div id="toast"></div>

<script>
const tg = window.Telegram.WebApp;
tg.ready(); tg.expand();
const initData = tg.initData;
const API = location.pathname;
let state = {user:null, config:null, tasks:null};

async function call(action, extra={}) {
  const fd = new FormData();
  fd.append('action', action);
  fd.append('initData', initData);
  for (const k in extra) fd.append(k, extra[k]);
  const r = await fetch(API + '?api=1', {method:'POST', body:fd});
  return r.json();
}
function toast(msg, color='#3b82f6') {
  const t = document.getElementById('toast');
  t.style.borderColor = color; t.textContent = msg; t.classList.add('show');
  clearTimeout(t._timer); t._timer = setTimeout(()=>t.classList.remove('show'), 3000);
}
function fmtTime(sec) {
  const h = Math.floor(sec/3600), m = Math.floor((sec%3600)/60), s = sec%60;
  return (h?h+'h ':'') + (m?m+'m ':'') + s+'s';
}
function esc(s) { return String(s||'').replace(/[&<>"']/g, c=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c])); }

function updateBell() {
  const c = state.user?.unread_notifications || 0;
  const b = document.getElementById('notifBadge');
  if (c > 0) { b.style.display='flex'; b.textContent = c > 99 ? '99+' : c; }
  else b.style.display = 'none';
}

function renderFaucet() {
  const u = state.user, c = state.config;
  const canClaim = u.next_claim_in <= 0;
  document.getElementById('page-faucet').innerHTML = `
    <div class="balance">
      <div class="sub">💵 Balance</div>
      <div class="num">${u.balance.toFixed(4)}</div>
      <div class="sub">${c.coin}</div>
    </div>
    <button class="btn ${canClaim?'btn-green':''}" id="claimBtn" ${canClaim?'':'disabled'}>
      ${canClaim ? '🎁 Claim '+c.claim_amount+' '+c.coin : '⏳ Next in '+fmtTime(u.next_claim_in)}
    </button>
    <div class="row" style="margin-top:14px">
      <div class="stat"><div class="v">${u.claims}</div><div class="l">Claims</div></div>
      <div class="stat"><div class="v">${(u.total_task_earned + u.total_bonus_earned + u.total_quiz_earned).toFixed(4)}</div><div class="l">From Bonus</div></div>
    </div>
    <div class="card" style="margin-top:14px">
      <div class="title">🔗 Referral</div>
      <div class="muted">Code: ${u.referral_code}</div>
      <button class="btn" id="refBtn">Share Invite</button>
    </div>
  `;
  if (canClaim) document.getElementById('claimBtn').onclick = doClaim;
  document.getElementById('refBtn').onclick = doRef;
}

function renderBonus() {
  const u = state.user;
  const streak = u.bonus_streak || 0;
  const canClaim = u.bonus_claimable;
  const rewards = [0.005,0.006,0.008,0.010,0.015,0.020,0.030];
  const nextStreak = canClaim ? (streak >= 7 ? 1 : (streak + 1)) : streak;
  let dayHtml = '';
  for (let i = 1; i <= 7; i++) {
    const done = i <= streak && !canClaim;
    const active = i === nextStreak && canClaim;
    dayHtml += `<div class="day ${active?'active':''} ${done?'done':''}">${i}</div>`;
  }
  document.getElementById('page-bonus').innerHTML = `
    <div class="card">
      <div class="title">🔥 Daily Bonus Streak</div>
      <div class="muted">প্রতিদিন ক্লেইম করলে বোনাস বাড়ে — Day 7 এ সর্বোচ্চ!</div>
      <div class="streak">${dayHtml}</div>
      <div class="muted" style="text-align:center;margin-top:8px">
        ${canClaim ? 'Next reward: ' + rewards[nextStreak-1] + ' ' + state.config.coin : 'Already claimed today ✅'}
      </div>
      <button class="btn ${canClaim?'btn-orange':''}" id="bonusBtn" ${canClaim?'':'disabled'}>
        ${canClaim ? '🔥 Claim Daily Bonus' : '✅ Claimed Today'}
      </button>
    </div>
    <div class="card"><div class="title">📝 Quiz</div><div id="quizArea" class="muted">Loading...</div></div>
    <div class="card"><div class="title">🏆 Leaderboard</div><div id="lbArea" class="muted">Loading...</div></div>
  `;
  if (canClaim) document.getElementById('bonusBtn').onclick = doDailyBonus;
  loadQuizzes();
  loadLeaderboard();
}

async function doDailyBonus() {
  const btn = document.getElementById('bonusBtn');
  btn.disabled = true; btn.innerHTML = '<span class="loader"></span>';
  const r = await call('daily_bonus');
  if (r.ok) {
    toast('🔥 +'+r.amount+' '+state.config.coin+' (Day '+r.streak+')', '#f59e0b');
    state.user.balance = r.new_balance;
    state.user.bonus_streak = r.streak;
    state.user.bonus_claimable = false;
    state.user.total_bonus_earned = (state.user.total_bonus_earned||0) + r.amount;
    renderBonus(); renderFaucet();
  } else { toast('❌ '+(r.err||'Failed'), '#ef4444'); refresh(); }
}

async function loadQuizzes() {
  const r = await call('quizzes_list');
  if (!r.ok) return;
  const el = document.getElementById('quizArea'); if (!el) return;
  if (r.quizzes.length === 0) { el.innerHTML = 'No quizzes'; return; }
  let html = '';
  r.quizzes.forEach(q => {
    html += `<div class="task ${q.attempted?'done':''}"><h4>${esc(q.question)}</h4><div class="pts">💰 ${q.points} ${state.config.coin}</div>`;
    if (q.attempted) html += `<div class="muted" style="margin-top:6px">${q.is_correct ? '✅ Correct! +'+q.points : '❌ Wrong. Correct: '+q.correct_answer}</div>`;
    else ['A','B','C','D'].forEach(k => {
      html += `<button class="opt" onclick="answerQuiz(${q.id},'${k}')">${k}. ${esc(q.options[k])}</button>`;
    });
    html += '</div>';
  });
  el.innerHTML = html;
}
async function answerQuiz(id, ans) {
  const r = await call('submit_quiz', {quiz_id: id, answer: ans});
  if (r.ok) {
    if (r.correct) toast('🎉 Correct! +'+r.points, '#26a17b');
    else toast('❌ Wrong! Answer: '+r.correct_answer, '#ef4444');
    state.user.balance = r.new_balance;
    loadQuizzes(); refresh();
  } else toast('❌ '+(r.err||'Failed'), '#ef4444');
}
async function loadLeaderboard() {
  const r = await call('leaderboard');
  if (!r.ok) return;
  const el = document.getElementById('lbArea'); if (!el) return;
  let html = '';
  const medals = ['🥇','🥈','🥉','4','5','6','7','8','9','10'];
  r.top.forEach((u, i) => {
    const me = u.id === state.user.id;
    html += `<div class="lb-row ${me?'me':''}"><div class="lb-rank">${medals[i]}</div>
      <div class="lb-name">${esc(u.name)}${u.username?' <span class="muted">@'+esc(u.username)+'</span>':''}</div>
      <div class="lb-amt">${u.total.toFixed(4)}</div></div>`;
  });
  html += `<div class="muted" style="text-align:center;margin-top:10px">Your rank: #${r.my_rank}</div>`;
  el.innerHTML = html;
}

async function openNotifications() {
  const r = await call('notifications');
  if (!r.ok) return;
  let html = '<div class="card"><div class="title">🔔 Notifications</div>';
  if (r.list.length === 0) html += '<div class="muted">No notifications</div>';
  else {
    r.list.forEach(n => {
      html += `<div class="notif ${n.type}"><h5>${esc(n.title)}</h5><p>${esc(n.message)}</p><small>${n.created_at}</small></div>`;
    });
    html += `<button class="btn" onclick="clearNotifs()" style="background:#ef4444">🗑️ Clear All</button>`;
  }
  html += '<button class="btn" onclick="closeNotifications()">Close</button></div>';
  let overlay = document.getElementById('notifOverlay');
  if (!overlay) {
    overlay = document.createElement('div');
    overlay.id = 'notifOverlay';
    overlay.style.cssText = 'position:fixed;inset:0;background:#0a0e27;z-index:200;padding:16px;overflow-y:auto';
    document.body.appendChild(overlay);
  }
  overlay.innerHTML = html;
  overlay.style.display = 'block';
  state.user.unread_notifications = 0;
  updateBell();
}
function closeNotifications() {
  const o = document.getElementById('notifOverlay');
  if (o) o.style.display = 'none';
}
async function clearNotifs() {
  await call('clear_notifications');
  closeNotifications();
  toast('✅ Cleared', '#26a17b');
}

function renderTasks() {
  if (!state.tasks) { document.getElementById('page-tasks').innerHTML = '<div style="text-align:center;padding:60px"><span class="loader"></span></div>'; return; }
  const t = state.tasks;
  let html = '<div class="card"><div class="title">🎯 Telegram Tasks</div>';
  if (t.telegram_tasks.length === 0) html += '<div class="muted">No tasks available</div>';
  t.telegram_tasks.forEach(task => {
    html += `<div class="task ${task.done?'done':''}">
      <h4>${esc(task.name)} ${task.done?'✅':''}</h4>
      <div class="desc">${esc(task.desc||'')}</div>
      <div>📢 ${esc(task.chat)}</div>
      <div class="pts">💰 ${task.points} ${state.config.coin}</div>
      ${task.done ? '' : `<div class="task-actions">
        <button class="btn btn-sm" onclick="window.open('https://t.me/${esc(task.chat.replace('@',''))}','_blank')">🔗 Join</button>
        <button class="btn btn-sm btn-green" onclick="completeTgTask(${task.id})">✅ Verify</button>
      </div>`}
    </div>`;
  });
  html += '</div><div class="card"><div class="title">🐦 Twitter Tasks</div>';
  if (!t.twitter_username) {
    html += `<div class="muted">⚠️ Set your Twitter username first (locked after)</div>
    <input id="twIn" placeholder="@username">
    <button class="btn" onclick="setTwitter()">Save Twitter Username</button>`;
  } else if (t.twitter_tasks.length === 0) {
    html += '<div class="muted">No Twitter tasks available</div>';
  } else {
    html += `<div class="muted" style="margin-bottom:12px">👤 Your Twitter: <b>@${esc(t.twitter_username)}</b> 🔒</div>`;
    t.twitter_tasks.forEach(task => {
      const st = task.status;
      const cls = st==='approved'?'done':(st==='pending'?'pending':'');
      const badge = st==='approved'?'✅':(st==='pending'?'⏳':(st==='rejected'?'❌':''));
      html += `<div class="task ${cls}"><h4>${esc(task.name)} ${badge}</h4>
        <div class="desc">${esc(task.desc||'')}</div>
        <div class="pts">💰 ${task.points} ${state.config.coin} | 🏷️ ${task.type}</div>
        ${st ? (st==='pending'?'<div class="muted">Waiting for admin approval</div>':'') :
          `<div class="task-actions">
            <button class="btn btn-sm" onclick="window.open('${esc(task.url)}','_blank')">🔗 Open</button>
            <button class="btn btn-sm btn-green" onclick="submitTw(${task.id})">✅ Submit</button>
          </div>`}
      </div>`;
    });
  }
  html += '</div>';
  document.getElementById('page-tasks').innerHTML = html;
}

function renderWallet() {
  const u = state.user, c = state.config;
  document.getElementById('page-wallet').innerHTML = `
    <div class="card">
      <div class="title">📧 FaucetPay Email</div>
      <div class="muted">${u.faucetpay_email ? '✅ '+esc(u.faucetpay_email) : '⚠️ Not set — required for withdrawal'}</div>
      ${u.faucetpay_email ? '' : `<input id="emailIn" type="email" placeholder="your@email.com">
        <button class="btn" onclick="setEmail()">Save FaucetPay Email</button>`}
    </div>
    <div class="card">
      <div class="title">💸 Withdraw</div>
      <div class="muted">Min: ${c.min_withdraw} ${c.coin}</div>
      <input id="wdAmt" type="number" step="0.0001" placeholder="Amount">
      <button class="btn" onclick="doWithdraw()">Withdraw to FaucetPay</button>
    </div>
    <div class="card"><div class="title">📜 History</div><div id="hist" class="muted">Loading...</div></div>
  `;
  loadHistory();
}

function renderProfile() {
  const u = state.user;
  document.getElementById('page-profile').innerHTML = `
    <div class="card"><div class="title">👤 ${esc(u.first_name)}</div><div class="muted">ID: #${u.id}</div></div>
    <div class="card">
      <div class="row">
        <div class="stat"><div class="v">${u.balance.toFixed(4)}</div><div class="l">Balance</div></div>
        <div class="stat"><div class="v">${u.total_claimed.toFixed(4)}</div><div class="l">Claimed</div></div>
      </div>
      <div class="row" style="margin-top:10px">
        <div class="stat"><div class="v">${u.total_task_earned.toFixed(4)}</div><div class="l">Tasks</div></div>
        <div class="stat"><div class="v">${u.total_bonus_earned.toFixed(4)}</div><div class="l">Bonus</div></div>
      </div>
      <div class="row" style="margin-top:10px">
        <div class="stat"><div class="v">${u.total_quiz_earned.toFixed(4)}</div><div class="l">Quiz</div></div>
        <div class="stat"><div class="v">${u.total_withdrawn.toFixed(4)}</div><div class="l">Withdrawn</div></div>
      </div>
    </div>
  `;
}

async function doClaim() {
  const btn = document.getElementById('claimBtn');
  btn.disabled = true; btn.innerHTML = '<span class="loader"></span>';
  const r = await call('claim');
  if (r.ok) {
    toast('🎉 +'+r.amount+' '+state.config.coin, '#26a17b');
    state.user.balance = r.new_balance; state.user.claims++; state.user.next_claim_in = r.next_claim_in;
    renderFaucet(); startCountdown();
  } else { toast('❌ '+(r.err||'Failed'), '#ef4444'); if (r.wait) { state.user.next_claim_in = r.wait; renderFaucet(); startCountdown(); } }
}
function doRef() {
  const link = 'https://t.me/<?= BOT_USERNAME ?>?start=' + state.user.referral_code;
  tg.openTelegramLink('https://t.me/share/url?url='+encodeURIComponent(link)+'&text='+encodeURIComponent('💵 Claim free '+state.config.coin+'!'));
}
async function setEmail() {
  const e = document.getElementById('emailIn').value.trim();
  if (!e) return toast('Enter email', '#ef4444');
  const r = await call('set_email', {email: e});
  if (r.ok) { toast('✅ Saved', '#26a17b'); refresh(); } else toast('❌ '+(r.err||'Failed'), '#ef4444');
}
async function doWithdraw() {
  const amt = parseFloat(document.getElementById('wdAmt').value);
  if (!amt) return toast('Enter amount', '#ef4444');
  const r = await call('withdraw', {amount: amt});
  if (r.ok) { toast('✅ Sent! TX: '+r.tx, '#26a17b'); refresh(); }
  else if (r.pending) { toast('⏳ Pending admin', '#f59e0b'); refresh(); }
  else toast('❌ '+(r.err||'Failed'), '#ef4444');
}
async function setTwitter() {
  const tw = document.getElementById('twIn').value.trim();
  if (!tw) return toast('Enter username', '#ef4444');
  const r = await call('set_twitter', {twitter: tw});
  if (r.ok) { toast('✅ Twitter saved (locked)', '#26a17b'); loadTasks(); refresh(); }
  else toast('❌ '+(r.err||'Failed'), '#ef4444');
}
async function completeTgTask(id) {
  const r = await call('complete_tg_task', {task_id: id});
  if (r.ok) { toast('🎉 +'+r.points+' '+state.config.coin, '#26a17b'); loadTasks(); refresh(); }
  else toast('❌ '+(r.err||'Failed'), '#ef4444');
}
async function submitTw(id) {
  const r = await call('submit_twitter', {task_id: id});
  if (r.ok) { toast('✅ Submitted! Awaiting approval', '#26a17b'); loadTasks(); }
  else toast('❌ '+(r.err||'Failed'), '#ef4444');
}
async function loadTasks() { const r = await call('tasks_list'); if (r.ok) { state.tasks = r; renderTasks(); } }
async function loadHistory() {
  const r = await call('history');
  if (!r.ok) return;
  let h = '';
  (r.claims||[]).forEach(c => h += `🟢 +${parseFloat(c.amount).toFixed(4)} <span class="muted">${c.created_at}</span><br>`);
  (r.withdrawals||[]).forEach(w => {
    const e = {completed:'✅',pending:'⏳',failed:'❌',processing:'🔄',rejected:'❌'}[w.status]||'❓';
    h += `${e} -${parseFloat(w.amount).toFixed(4)} <span class="muted">${w.status}</span><br>`;
  });
  const el = document.getElementById('hist'); if (el) el.innerHTML = h || 'No history';
}
function startCountdown() {
  clearInterval(window._cd);
  window._cd = setInterval(() => {
    if (!state.user) return;
    state.user.next_claim_in--;
    if (state.user.next_claim_in <= 0) { clearInterval(window._cd); state.user.next_claim_in = 0; renderFaucet(); return; }
    const btn = document.getElementById('claimBtn');
    if (btn) btn.textContent = '⏳ Next in '+fmtTime(state.user.next_claim_in);
  }, 1000);
}
async function refresh() {
  const r = await call('me');
  if (!r.ok) return toast('Auth failed. Open from Telegram.', '#ef4444');
  state.user = r.user; state.config = r.config;
  renderFaucet(); renderWallet(); renderProfile();
  if (document.getElementById('page-bonus').classList.contains('active')) renderBonus();
  updateBell();
  if (state.user.next_claim_in > 0) startCountdown();
}
document.querySelectorAll('.nav button').forEach(b => {
  b.onclick = () => {
    document.querySelectorAll('.nav button').forEach(x=>x.classList.remove('active'));
    document.querySelectorAll('.page').forEach(x=>x.classList.remove('active'));
    b.classList.add('active');
    document.getElementById('page-'+b.dataset.tab).classList.add('active');
    if (b.dataset.tab === 'tasks') loadTasks();
    if (b.dataset.tab === 'wallet') loadHistory();
    if (b.dataset.tab === 'bonus') renderBonus();
  };
});
window.completeTgTask = completeTgTask;
window.submitTw = submitTw;
window.setTwitter = setTwitter;
window.setEmail = setEmail;
window.doWithdraw = doWithdraw;
window.answerQuiz = answerQuiz;
window.openNotifications = openNotifications;
window.closeNotifications = closeNotifications;
window.clearNotifs = clearNotifs;

refresh();
setTimeout(loadTasks, 800);
</script>
</body>
</html>
    <?php
}

// ==================== ROUTER ====================
try {
    if (isset($_GET['install'])) install();
    elseif (isset($_GET['webhook'])) {
        $u = json_decode(file_get_contents('php://input'), true);
        if ($u) {
            if (isset($u['message'])) handleBot($u);
            elseif (isset($u['callback_query'])) handleCallback($u['callback_query']);
        }
        echo "OK";
    }
    elseif (isset($_GET['api'])) api();
    elseif (isset($_GET['worker'])) worker();
    elseif (isset($_GET['debug_chat'])) debugChat();
    else miniApp();
} catch (Exception $e) {
    error_log("FAUCET ERROR: " . $e->getMessage());
    if (isset($_GET['api'])) { header('Content-Type: application/json'); echo json_encode(['ok'=>false,'err'=>'Server error']); }
    else echo "Server error.";
}