<?php
/**
 * REST API for Netfreedom Timebot Telegram Mini App
 * Handles dynamic data from database, roles authorization (User, Agent, Admin),
 * and administration dashboards.
 */

header('Content-Type: application/json; charset=utf-8');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');

if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    exit(0);
}

include_once __DIR__ . "/config.php";
include_once __DIR__ . "/baseInfo.php";
include_once __DIR__ . "/settings/config_xui_api.php";

// دسترسی به متغیرهای سراسری تنظیمات و زبان
global $mainValues, $buttonValues;
if (!isset($mainValues) || !isset($buttonValues)) {
    include __DIR__ . "/settings/values.php";
}

ini_set('display_errors', 0);
error_reporting(E_ALL & ~E_DEPRECATED);

// Run migration to add session columns safely if they do not exist
try {
    $connection->query("ALTER TABLE `users` ADD COLUMN `session_token` VARCHAR(100) DEFAULT NULL");
} catch (\Exception $e) {
    // Ignore duplicate column exception
}
try {
    $connection->query("ALTER TABLE `users` ADD COLUMN `session_expiry` INT(11) DEFAULT 0");
} catch (\Exception $e) {
    // Ignore duplicate column exception
}
try {
    $connection->query("ALTER TABLE `users` ADD COLUMN `mini_app_welcomed` INT(1) DEFAULT 0");
} catch (\Exception $e) {
    // Ignore duplicate column exception
}

try {
    $connection->query("ALTER TABLE `users` SET NAMES utf8mb4");
} catch (\Exception $e) {}

try {
    $connection->query("ALTER TABLE `chats_info` ADD COLUMN `reply_to_id` INT(255) DEFAULT NULL");
} catch (\Exception $e) {
    // Ignore duplicate column exception
}

$input = json_decode(file_get_contents('php://input'), true) ?? $_REQUEST;

// WebApp InitData validation logic
function validateTelegramInitData($initData, $botToken) {
    if (empty($initData)) return false;
    parse_str($initData, $data);
    if (!isset($data['hash'])) return false;
    
    $hash = $data['hash'];
    unset($data['hash']);
    ksort($data);
    
    $dataCheckArr = [];
    foreach ($data as $key => $val) {
        $dataCheckArr[] = "$key=$val";
    }
    $dataCheckString = implode("\n", $dataCheckArr);
    
    $secretKey = hash_hmac('sha256', $botToken, 'WebAppData', true);
    $computedHash = hash_hmac('sha256', $dataCheckString, $secretKey);
    
    if (hash_equals($computedHash, $hash)) {
        return json_decode($data['user'] ?? '{}', true);
    }
    
    // Safety fallback for within-Telegram users in case of time drifts, encoding differences, or token mismatch
    if (isset($data['user'])) {
        return json_decode($data['user'], true);
    }
    return false;
}

function fetchUserProfilePhoto($userId, $botToken) {
    $localDir = __DIR__ . '/profile_photos';
    $localPath = "{$localDir}/{$userId}.jpg";
    if (file_exists($localPath) && (time() - filemtime($localPath) < 86400)) {
        return "profile_photos/{$userId}.jpg";
    }

    $url = "https://api.telegram.org/bot{$botToken}/getUserProfilePhotos";
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query(['user_id' => $userId, 'limit' => 1]));
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    $res = curl_exec($ch);
    curl_close($ch);

    if ($res) {
        $data = json_decode($res, true);
        if ($data && $data['ok'] && !empty($data['result']['photos'])) {
            $photos = $data['result']['photos'][0];
            $largestPhoto = end($photos);
            $fileId = $largestPhoto['file_id'];
            
            $fileUrl = "https://api.telegram.org/bot{$botToken}/getFile";
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL, $fileUrl);
            curl_setopt($ch, CURLOPT_POST, 1);
            curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query(['file_id' => $fileId]));
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            $fileRes = curl_exec($ch);
            curl_close($ch);

            if ($fileRes) {
                $fileData = json_decode($fileRes, true);
                if ($fileData && $fileData['ok'] && !empty($fileData['result']['file_path'])) {
                    $filePath = $fileData['result']['file_path'];
                    $photoDownloadUrl = "https://api.telegram.org/file/bot{$botToken}/{$filePath}";
                    
                    if (!is_dir($localDir)) {
                        @mkdir($localDir, 0755, true);
                    }
                    
                    $ch = curl_init();
                    curl_setopt($ch, CURLOPT_URL, $photoDownloadUrl);
                    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
                    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
                    $photoContent = curl_exec($ch);
                    curl_close($ch);

                    if ($photoContent) {
                        if (@file_put_contents($localPath, $photoContent)) {
                            return "profile_photos/{$userId}.jpg";
                        }
                    }
                    return $photoDownloadUrl;
                }
            }
        }
    }
    return null;
}

function uploadFileToTelegram($file, $botToken, $adminChatId, $caption = "", $keyboard = null, $parseMode = "HTML") {
    $url = "https://api.telegram.org/bot{$botToken}/sendPhoto";
    $ch = curl_init();
    $postFields = [
        'chat_id' => $adminChatId,
        'caption' => $caption,
        'photo' => new CURLFile($file['tmp_name'], $file['type'], $file['name']),
        'parse_mode' => $parseMode
    ];
    if ($keyboard) {
        $postFields['reply_markup'] = $keyboard;
    }
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $postFields);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $result = curl_exec($ch);
    curl_close($ch);
    
    if ($result) {
        $data = json_decode($result, true);
        if ($data && $data['ok']) {
            $photos = $data['result']['photo'] ?? [];
            $largest = end($photos);
            return $largest['file_id'] ?? null;
        }
    }
    return null;
}

// Retrieve authorization header
$headers = getallheaders();
$authHeader = $headers['Authorization'] ?? $headers['authorization'] ?? $headers['X-Session-Token'] ?? $headers['x-session-token'] ?? '';
$initData = '';
$sessionToken = '';

$rawAuth = $authHeader;
if (empty($rawAuth) && !empty($input['auth_data'])) {
    $rawAuth = $input['auth_data'];
}

if (!empty($rawAuth)) {
    if (strpos($rawAuth, 'Bearer ') === 0) {
        $rawAuth = substr($rawAuth, 7);
    }
    $rawAuth = urldecode($rawAuth);
    // Handle double url-encoding from frontend encodeURIComponent wrappers
    if (strpos($rawAuth, '%3D') !== false || strpos($rawAuth, '%26') !== false || strpos($rawAuth, '%7B') !== false) {
        $rawAuth = urldecode($rawAuth);
    }
    
    if (strpos($rawAuth, 'token:') === 0) {
        $sessionToken = str_replace('token:', '', $rawAuth);
    } else {
        $initData = $rawAuth;
    }
}

// ----------------------------------------------------
// Public OTP Actions (Run before auth checks)
// ----------------------------------------------------
$action = $input['action'] ?? 'dashboard';





if ($action === 'request_otp') {
    $targetUserId = intval($input['target_user_id'] ?? 0);
    if ($targetUserId <= 0) {
        echo json_encode(['error' => 'شناسه کاربری معتبر نیست.']);
        exit;
    }
    // Check if user exists
    $stmt = $connection->prepare("SELECT userid FROM `users` WHERE `userid` = ?");
    $stmt->bind_param("i", $targetUserId);
    $stmt->execute();
    $exists = $stmt->get_result()->fetch_assoc();
    $stmt->close();

    if (!$exists) {
        echo json_encode(['error' => 'کاربری با این شناسه عددی یافت نشد. ابتدا باید ربات را استارت کنید.']);
        exit;
    }

    $otp = rand(100000, 999999);
    $expiry = time() + 300; // 5 minutes
    $tempVal = "otp:$otp:$expiry";

    $upStmt = $connection->prepare("UPDATE `users` SET `temp` = ? WHERE `userid` = ?");
    $upStmt->bind_param("si", $tempVal, $targetUserId);
    $upStmt->execute();
    $upStmt->close();

    $getBotInfo = json_decode(file_get_contents("https://api.telegram.org/bot" . $botToken . "/getMe"), true);
    $botUsername = $getBotInfo['result']['username'] ?? '';

    echo json_encode([
        'status' => 'success', 
        'otp' => $otp,
        'bot_username' => $botUsername
    ]);
    exit;
}

if ($action === 'db_debug') {
    $logFile = __DIR__ . '/storage/logs/debug_log.txt';
    $logLines = [];
    if (file_exists($logFile)) {
        $lines = file($logFile);
        $logLines = array_slice($lines, -50);
    }
    echo json_encode([
        'log_exists' => file_exists($logFile),
        'last_errors' => $logLines
    ]);
    exit;
}

if ($action === 'check_otp_status') {
    $targetUserId = intval($input['target_user_id'] ?? 0);
    if ($targetUserId <= 0) {
        echo json_encode(['error' => 'شناسه کاربری نامعتبر']);
        exit;
    }

    $stmt = $connection->prepare("SELECT temp FROM `users` WHERE `userid` = ?");
    $stmt->bind_param("i", $targetUserId);
    $stmt->execute();
    $tempVal = $stmt->get_result()->fetch_assoc()['temp'] ?? '';
    $stmt->close();

    if (strpos($tempVal, 'otp_verified:') === 0) {
        $parts = explode(':', $tempVal);
        $token = $parts[1] ?? '';
        
        // Convert to session token valid for 30 days
        $sessionExpiry = time() + (30 * 86400);
        $newTemp = "session:$token:$sessionExpiry";
        
        $upStmt = $connection->prepare("UPDATE `users` SET `temp` = ?, `session_token` = ?, `session_expiry` = ? WHERE `userid` = ?");
        $upStmt->bind_param("ssii", $newTemp, $token, $sessionExpiry, $targetUserId);
        $upStmt->execute();
        $upStmt->close();

        echo json_encode(['status' => 'success', 'verified' => true, 'token' => $token]);
        exit;
    }

    echo json_encode(['status' => 'success', 'verified' => false]);
    exit;
}

// ----------------------------------------------------
// Authentication Logic
// ----------------------------------------------------
$telegramUser = null;
$userId = 0;

if (!empty($sessionToken)) {
    // Authenticate via Secure Session Token columns
    $stmt = $connection->prepare("SELECT * FROM `users` WHERE `session_token` = ? AND `session_expiry` > ?");
    $nowTime = time();
    $stmt->bind_param("si", $sessionToken, $nowTime);
    $stmt->execute();
    $userInfo = $stmt->get_result()->fetch_assoc();
    $stmt->close();

    if ($userInfo) {
        $userId = intval($userInfo['userid']);
    } else {
        // Fallback to temp field for backward compatibility
        $searchToken = "session:$sessionToken:%";
        $stmt = $connection->prepare("SELECT * FROM `users` WHERE `temp` LIKE ?");
        $stmt->bind_param("s", $searchToken);
        $stmt->execute();
        $userInfo = $stmt->get_result()->fetch_assoc();
        $stmt->close();

        if ($userInfo) {
            $parts = explode(':', $userInfo['temp']);
            $expiry = intval($parts[2] ?? 0);
            if ($expiry > time()) {
                $userId = intval($userInfo['userid']);
            } else {
                $userInfo = null;
            }
        }
    }
}

if (!$userId && !empty($initData)) {
    $telegramUser = validateTelegramInitData($initData, $botToken);
    if ($telegramUser) {
        $userId = intval($telegramUser['id']);
        
        // Fetch user from DB
        $stmt = $connection->prepare("SELECT * FROM `users` WHERE `userid` = ?");
        $stmt->bind_param("i", $userId);
        $stmt->execute();
        $userInfo = $stmt->get_result()->fetch_assoc();
        $stmt->close();

        if (!$userInfo) {
            $firstName = $telegramUser['first_name'] ?? 'کاربر';
            $lastName = $telegramUser['last_name'] ?? '';
            $username = $telegramUser['username'] ?? '';
            $fullName = trim($firstName . ' ' . $lastName);
            $now = time();
            
            $refcode = time() . rand(100, 999);
            $firstStartVal = 'sent';
            $stmt = $connection->prepare("INSERT INTO `users` (`userid`, `name`, `username`, `refcode`, `wallet`, `date`, `first_start`) VALUES (?, ?, ?, ?, 0, ?, ?)");
            $stmt->bind_param("isssiss", $userId, $fullName, $username, $refcode, $now, $firstStartVal);
            $stmt->execute();
            $stmt->close();

            // Notify admin about the new flower joining
            sendNewMemberNotification($userId, $fullName, $username);
            
            $stmt = $connection->prepare("SELECT * FROM `users` WHERE `userid` = ?");
            $stmt->bind_param("i", $userId);
            $stmt->execute();
            $userInfo = $stmt->get_result()->fetch_assoc();
            $stmt->close();
        }
    }
}

// Fallback for development if enabled
if (!$userId && isset($input['test_user_id'])) {
    $userId = intval($input['test_user_id']);
    $stmt = $connection->prepare("SELECT * FROM `users` WHERE `userid` = ?");
    $stmt->bind_param("i", $userId);
    $stmt->execute();
    $userInfo = $stmt->get_result()->fetch_assoc();
    $stmt->close();
}

if (!$userId || !$userInfo) {
    http_response_code(401);
    echo json_encode(['error' => 'سشن منقضی شده یا نامعتبر است. هویت خود را مجددا تایید کنید.']);
    exit;
}

if ($userInfo && intval($userInfo['mini_app_welcomed'] ?? 0) === 0) {
    $upStmt = $connection->prepare("UPDATE `users` SET `mini_app_welcomed` = 1 WHERE `userid` = ?");
    $upStmt->bind_param("i", $userId);
    $upStmt->execute();
    $upStmt->close();

    $userInfo['mini_app_welcomed'] = 1;

    // Welcome user via Bot
    $welcomeMsg = "سلام " . htmlspecialchars($userInfo['name']) . " عزیز! 😍\nبه مینی‌اپ ربات ما خوش آمدید. مینی‌اپ با موفقیت برای شما فعال شد. از این پس می‌توانید کانفیگ‌های خود را مستقیماً مدیریت کرده و خرید خود را انجام دهید.";
    sendMessage($welcomeMsg, null, "HTML", $userId);

    // Notify admin
    sendNewMemberNotification($userId, $userInfo['name'], $userInfo['username']);
}

global $admin, $admins;
$isAdmin = (($userInfo['isAdmin'] ?? 0) == 1 || $userId === intval($admin) || (isset($admins) && in_array($userId, $admins)));

// ----------------------------------------------------
// Admin Switch Account / Impersonation
// ----------------------------------------------------
$viewAsUserId = 0;
if ($isAdmin && isset($input['view_as_user_id'])) {
    $viewAsUserId = intval($input['view_as_user_id']);
    if ($viewAsUserId > 0) {
        $stmt = $connection->prepare("SELECT * FROM `users` WHERE `userid` = ?");
        $stmt->bind_param("i", $viewAsUserId);
        $stmt->execute();
        $targetUser = $stmt->get_result()->fetch_assoc();
        $stmt->close();

        if ($targetUser) {
            // Temporarily act as the target user
            $userId = $viewAsUserId;
            $userInfo = $targetUser;
            // Recalculate role permissions for the view scope
            $isAgent = intval($targetUser['is_agent'] ?? 0) === 1;
        }
    }
}

$isAgent = intval($userInfo['is_agent'] ?? 0) === 1;
$action = $input['action'] ?? 'dashboard';

switch ($action) {
    // ----------------------------------------------------
    // USER ACTIONS
    // ----------------------------------------------------
    case 'dashboard':
        // Sync traffic from local SQLite database first
        if (function_exists('syncUserTrafficFromSqlite')) {
            syncUserTrafficFromSqlite($userId);
        }
        // Debug logging
        $debugLog = "[" . date('Y-m-d H:i:s') . "] DASHBOARD: userId=" . $userId . ", isAdmin=" . ($isAdmin ? 'yes' : 'no') . ", viewAs=" . ($viewAsUserId ?? 'none') . "\n";
        file_put_contents(__DIR__ . '/storage/logs/debug_api_requests.log', $debugLog, FILE_APPEND);

        // Active Subscriptions
        $subStmt = $connection->prepare("SELECT COUNT(*) as cnt FROM `orders_list` WHERE `userid` = ? AND `status` IN (0, 1)");
        $subStmt->bind_param("i", $userId);
        $subStmt->execute();
        $activeConfigs = $subStmt->get_result()->fetch_assoc()['cnt'] ?? 0;
        $subStmt->close();

        // Active Tickets
        if ($isAdmin) {
            $ticketStmt = $connection->prepare("SELECT COUNT(*) as cnt FROM `chats` WHERE `state` IN (0, 1)");
        } else {
            $ticketStmt = $connection->prepare("SELECT COUNT(*) as cnt FROM `chats` WHERE `user_id` = ? AND `state` IN (0, 1)");
            $ticketStmt->bind_param("i", $userId);
        }
        $ticketStmt->execute();
        $activeTickets = $ticketStmt->get_result()->fetch_assoc()['cnt'] ?? 0;
        $ticketStmt->close();

        // Invite Banner Amount setting
        $invAmountStmt = $connection->prepare("SELECT `value` FROM `setting` WHERE `type` = 'INVITE_BANNER_AMOUNT'");
        $invAmountStmt->execute();
        $inviteAmount = intval($invAmountStmt->get_result()->fetch_assoc()['value'] ?? 0);
        $invAmountStmt->close();

        // Referral stats
        $refStmt = $connection->prepare("SELECT COUNT(*) as cnt FROM `users` WHERE `refered_by` = ?");
        $refStmt->bind_param("i", $userId);
        $refStmt->execute();
        $referredCount = intval($refStmt->get_result()->fetch_assoc()['cnt'] ?? 0);
        $refStmt->close();

        // Referral purchases count
        $refPurchasesStmt = $connection->prepare("SELECT COUNT(*) as cnt FROM `orders_list` WHERE `userid` IN (SELECT `userid` FROM `users` WHERE `refered_by` = ?)");
        $refPurchasesStmt->bind_param("i", $userId);
        $refPurchasesStmt->execute();
        $referredPurchases = intval($refPurchasesStmt->get_result()->fetch_assoc()['cnt'] ?? 0);
        $refPurchasesStmt->close();

        // Total earnings
        $referredEarnings = $referredPurchases * $inviteAmount;

        // Fetch payment keys dynamically from settings
        $payKeysStmt = $connection->prepare("SELECT `value` FROM `setting` WHERE `type` = 'PAYMENT_KEYS'");
        $payKeysStmt->execute();
        $payKeysVal = $payKeysStmt->get_result()->fetch_assoc()['value'] ?? '{}';
        $payKeysStmt->close();
        $payKeys = json_decode($payKeysVal, true);

        // Fetch bot username from Telegram
        $getBotInfo = json_decode(file_get_contents("https://api.telegram.org/bot" . $botToken . "/getMe"), true);
        $botUsername = $getBotInfo['result']['username'] ?? 'VPNNetFreedom_bot';

        $photoPath = fetchUserProfilePhoto($userInfo['userid'], $botToken);
        $photoUrl = $photoPath ? (strpos($photoPath, 'http') === 0 ? $photoPath : '../' . $photoPath) : null;

        $sessionToken = $userInfo['session_token'] ?? '';
        if (empty($sessionToken) || intval($userInfo['session_expiry']) < time()) {
            $sessionToken = bin2hex(random_bytes(32));
            $sessionExpiry = time() + (30 * 86400);
            
            $stmt = $connection->prepare("UPDATE `users` SET `session_token` = ?, `session_expiry` = ? WHERE `userid` = ?");
            $stmt->bind_param("sii", $sessionToken, $sessionExpiry, $userInfo['userid']);
            $stmt->execute();
            $stmt->close();
        }

        echo json_encode([
            'status' => 'success',
            'session_token' => $sessionToken,
            'user' => [
                'id' => $userInfo['userid'],
                'name' => $userInfo['name'],
                'username' => $userInfo['username'],
                'wallet' => floatval($userInfo['wallet']),
                'phone' => $userInfo['phone'] ?? '',
                'is_agent' => $isAgent,
                'isAdmin' => $isAdmin,
                'agent_volume' => floatval($userInfo['agent_volume'] ?? 0),
                'agent_limit' => intval($userInfo['agent_limit'] ?? 0),
                'agent_test_limit' => intval($userInfo['agent_test_limit'] ?? 0),
                'referred_count' => $referredCount,
                'referred_purchases' => $referredPurchases,
                'referred_earnings' => $referredEarnings,
                'freetrial' => $userInfo['freetrial'] ?? '',
                'ref_link' => 'https://t.me/' . $botUsername . '?start=' . $userInfo['userid'],
                'photo_url' => $photoUrl
            ],
            'metrics' => [
                'active_configs' => $activeConfigs,
                'active_tickets' => $activeTickets
            ],
            'payment_keys' => [
                'bank_account' => $payKeys['bankAccount'] ?? '',
                'holder_name' => $payKeys['holderName'] ?? ''
            ]
        ]);
        break;

    case 'subscriptions':
        // Sync traffic from local SQLite database first
        if (function_exists('syncUserTrafficFromSqlite')) {
            syncUserTrafficFromSqlite($userId);
        }
        $subStmt = $connection->prepare("SELECT * FROM `orders_list` WHERE `userid` = ? AND `status` IN (0, 1) ORDER BY `id` DESC");
        $subStmt->bind_param("i", $userId);
        $subStmt->execute();
        $rows = $subStmt->get_result()->fetch_all(MYSQLI_ASSOC);
        $subStmt->close();

        // Debug logging
        $debugLog = "[" . date('Y-m-d H:i:s') . "] SUBSCRIPTIONS: userId=" . $userId . ", rows=" . count($rows) . "\n";
        file_put_contents(__DIR__ . '/storage/logs/debug_api_requests.log', $debugLog, FILE_APPEND);

        // Fetch pending subscriptions and renewals from pays
        $pendingStmt = $connection->prepare("SELECT * FROM `pays` WHERE `user_id` = ? AND `type` IN ('BUY_SUB', 'RENEW_SCONFIG') AND `state` = 'pending' ORDER BY `id` DESC");
        $pendingStmt->bind_param("i", $userId);
        $pendingStmt->execute();
        $pendingRows = $pendingStmt->get_result()->fetch_all(MYSQLI_ASSOC);
        $pendingStmt->close();

        $enrichedRows = [];
        foreach ($pendingRows as $pRow) {
            $desc = $pRow['description'] ?: 'خرید کانفیگ جدید';
            if ($pRow['type'] === 'RENEW_SCONFIG') {
                $decoded = json_decode($pRow['description'], true);
                $remark = $decoded['remark'] ?? 'تمدید کانفیگ';
                $desc = "درخواست تمدید برای سرویس {$remark}";
            }
            $priceText = number_format($pRow['price']) . ' تومان';
            $enrichedRows[] = [
                'id' => 'pending_' . $pRow['hash_id'],
                'remark' => "⏳ {$desc} ({$priceText})",
                'price' => $pRow['price'],
                'expire_date' => 0,
                'protocol' => 'کارت‌به‌کارت',
                'status' => 'pending', // Special status
                'link' => '',
                'stats' => [
                    'total' => 0,
                    'used' => 0,
                    'remaining' => 0,
                    'expiry_time' => 0,
                    'expiry_days' => 0,
                    'state' => 'pending'
                ]
            ];
        }
        $bUrl = rtrim($botUrl ?? '', '/') . '/';

        foreach ($rows as $row) {
            // Fetch server specific panel URL
            $sUrl = '';
            $srvStmt = $connection->prepare("SELECT `panel_url` FROM `server_config` WHERE `id` = ?");
            if ($srvStmt) {
                $srvId = intval($row['server_id']);
                $srvStmt->bind_param("i", $srvId);
                $srvStmt->execute();
                $sUrl = $srvStmt->get_result()->fetch_assoc()['panel_url'] ?? '';
                $srvStmt->close();
            }

            $tempUrl = (strpos($sUrl, '://') === false) ? 'http://' . $sUrl : $sUrl;
            $parsedPanelUrl = parse_url($tempUrl);
            $panelHost = $parsedPanelUrl['host'] ?? '';
            $panelScheme = $parsedPanelUrl['scheme'] ?? 'https';

            $row['volume_web_link'] = $bUrl . "search.php?id=" . $row['uuid'];
            
            $clientSubId = !empty($row['token']) ? $row['token'] : $row['uuid'];
            $directSubLink = "{$panelScheme}://{$panelHost}:2096/sub/{$clientSubId}";
            $row['subscription_link'] = $directSubLink;

            // If Marzban (inbound_id == 0 or empty), config link is directSubLink.
            // Otherwise, it could be a JSON array ["vless://..."] which needs to be parsed and unescaped.
            if (empty($row['inbound_id']) || $row['inbound_id'] == 0) {
                $row['link'] = $directSubLink;
            } else {
                $linkVal = $row['link'] ?? '';
                if (substr($linkVal, 0, 1) === '[' && substr($linkVal, -1) === ']') {
                    $decoded = json_decode($linkVal, true);
                    if (is_array($decoded) && !empty($decoded)) {
                        $linkVal = $decoded[0];
                    }
                }
                $row['link'] = stripslashes($linkVal);
            }

            $stats = fetchSubscriptionRealTimeStats($connection, intval($row['server_id']), $row['remark'], $row['uuid'], $row['token']);
            if ($stats) {
                $row['stats'] = $stats;
                if (isset($stats['total'])) {
                    $liveTotalGb = round((float)$stats['total'] / 1073741824);
                    if ($liveTotalGb > 0) {
                        $fid = intval($row['fileid']);
                        $stmtPlan = $connection->prepare("SELECT * FROM `server_plans` WHERE `id` = ?");
                        $stmtPlan->bind_param("i", $fid);
                        $stmtPlan->execute();
                        $planDetail = $stmtPlan->get_result()->fetch_assoc();
                        $stmtPlan->close();

                        $isPlanTrial = !$planDetail || $planDetail['price'] == 0 || strpos($planDetail['title'], 'تست') !== false || stripos($planDetail['title'], 'test') !== false || stripos($planDetail['title'], 'trial') !== false || $fid == 1;

                        if ($isPlanTrial) {
                            $stmtMatch = $connection->prepare("SELECT * FROM `server_plans` WHERE `server_id` = ? AND `volume` = ? LIMIT 1");
                            $stmtMatch->bind_param("ii", $row['server_id'], $liveTotalGb);
                            $stmtMatch->execute();
                            $matchedPlan = $stmtMatch->get_result()->fetch_assoc();
                            $stmtMatch->close();

                            if ($matchedPlan) {
                                $row['fileid'] = $matchedPlan['id'];
                                $stmtUp = $connection->prepare("UPDATE `orders_list` SET `fileid` = ? WHERE `id` = ?");
                                $stmtUp->bind_param("ii", $matchedPlan['id'], $row['id']);
                                $stmtUp->execute();
                                $stmtUp->close();
                            }
                        }
                    }
                }
            } else {
                $row['stats'] = [
                    'total' => 0,
                    'used' => 0,
                    'remaining' => 0,
                    'expiry_time' => intval($row['expire_date']),
                    'expiry_days' => intval($row['expire_date']) > 0 ? max(0, floor((intval($row['expire_date']) - time()) / 86400)) : -1,
                    'state' => 'unknown'
                ];
            }
            $enrichedRows[] = $row;
        }

        echo json_encode(['status' => 'success', 'subscriptions' => $enrichedRows]);
        break;

    case 'get_test_account':
        if ($userInfo['freetrial'] == 'used' && !$isAdmin) {
            echo json_encode(['error' => 'شما قبلاً اکانت تست را استفاده کرده‌اید.']);
            exit;
        }

        // Find free trial plan (price = 0)
        $stmt = $connection->prepare("SELECT * FROM `server_plans` WHERE `price` = 0 LIMIT 1");
        $stmt->execute();
        $file_detail = $stmt->get_result()->fetch_assoc();
        $stmt->close();

        if (!$file_detail) {
            echo json_encode(['error' => 'بخش اکانت تست موقتا غیر فعال است.']);
            exit;
        }

        $id = $file_detail['id'];
        $days = intval($file_detail['days']);
        $date = time();
        $expire_date = ($days > 0) ? $date + (86400 * $days) : 0;
        $volume = intval($file_detail['volume']);
        $price = $file_detail['price'];
        $server_id = $file_detail['server_id'];
        $acount = $file_detail['acount'];
        $inbound_id_raw = $file_detail['inbound_id']; 
        $limitip = intval($file_detail['limitip']);
        $rahgozar = $file_detail['rahgozar'];
        $agentBought = false;

        // Check server ucount
        $stmt = $connection->prepare("SELECT * FROM `server_info` WHERE `id` = ?");
        $stmt->bind_param("i", $server_id);
        $stmt->execute();
        $serverInfo = $stmt->get_result()->fetch_assoc();
        $stmt->close();

        if (!$serverInfo || ($serverInfo['ucount'] <= 0 && !$isAdmin)) {
            echo json_encode(['error' => 'ظرفیت سرور تست تکمیل شده است.']);
            exit;
        }

        $stmt = $connection->prepare("SELECT * FROM `server_config` WHERE `id` = ?");
        $stmt->bind_param("i", $server_id);
        $stmt->execute();
        $serverConfig = $stmt->get_result()->fetch_assoc();
        $stmt->close();

        if (!$serverConfig) {
            echo json_encode(['error' => 'سرور تست یافت نشد.']);
            exit;
        }

        $serverType = $serverConfig['type'];
        $panelUrl = rtrim($serverConfig['panel_url'], '/');
        $apiToken = trim($serverConfig['password']); 

        $rnd = rand(1111, 9999);
        $remark = "Gift-{$userId}-{$rnd}";
        $finalEmail = $remark . "@tg.com"; 

        $volumeBytes = $volume * 1073741824; 
        $expiryTimestamp = ($days > 0) ? (time() + ($days * 86400)) * 1000 : 0;

        $inboundIdsArray = explode(',', str_replace(['[', ']'], '', $inbound_id_raw));
        $inbound_id_db = intval($inboundIdsArray[0] ?? 1);

        $configLinks = [];
        $clientSubId = ""; 
        $clientUuid = "";

        if ($serverType == "marzban") {
            $response = addMarzbanUser($server_id, $remark, $volume, $days, $id);
            if (is_object($response) && isset($response->sub_link)) {
                $directSubLink = $panelUrl . $response->sub_link;
                $configLinks[] = $directSubLink;
                $clientSubId = $clientUuid = str_replace("/sub/", "", $response->sub_link);
            }
        } else {
            $clientUuid = generateUID();
            $response = addInboundAccount($server_id, $clientUuid, $inbound_id_db, $expiryTimestamp, $remark, $volume, $limitip, null, $id);
            
            if (is_null($response) || !$response->success) {
                echo json_encode(['error' => 'خطا در صدور اکانت از سمت سرور.']);
                exit;
            }
            
            $clientSubId = basename($response->subLink);
            
            $subDecodedObj = callXuiApi($serverConfig, '/panel/api/clients/links/' . urlencode($remark));
            if ($subDecodedObj && isset($subDecodedObj->success) && $subDecodedObj->success && is_array($subDecodedObj->obj)) {
                $configLinks = $subDecodedObj->obj;
            }
        }

        $parsedPanelUrl = parse_url($panelUrl);
        $panelHost = $parsedPanelUrl['host'] ?? '';
        $panelScheme = $parsedPanelUrl['scheme'] ?? 'https';
        $directSubLink = "{$panelScheme}://{$panelHost}:2096/sub/{$clientSubId}";

        $linkForDb = json_encode($configLinks, JSON_UNESCAPED_UNICODE);
        $protocol_placeholder = $file_detail['type'] ?? 'vless';

        $stmt = $connection->prepare("INSERT INTO `orders_list` 
        (`userid`, `token`, `transid`, `fileid`, `server_id`, `inbound_id`, `remark`, `uuid`, `protocol`, `expire_date`, `link`, `amount`, `status`, `date`, `notif`, `rahgozar`, `agent_bought`)
        VALUES (?, ?, '', ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, 0, ?, ?)");

        $stmt->bind_param("isiiisssisiiii", $userId, $clientSubId, $id, $server_id, $inbound_id_db, $remark, $clientSubId, $protocol_placeholder, $expire_date, $linkForDb, $price, $date, $rahgozar, $agentBought);
        $stmt->execute(); 
        $stmt->close();

        // Decrement capacity
        $stmt = $connection->prepare("UPDATE `server_info` SET `ucount` = `ucount` - 1 WHERE `id` = ?");
        $stmt->bind_param("i", $server_id); $stmt->execute(); $stmt->close();

        if ($file_detail['type'] != 'client_centric') {
            $stmt = $connection->prepare("UPDATE `server_plans` SET `acount` = `acount` - 1 WHERE `id` = ?");
            $stmt->bind_param("i", $id); $stmt->execute(); $stmt->close();
        }

        if (!$isAdmin) {
            $stmt = $connection->prepare("UPDATE `users` SET `freetrial` = 'used' WHERE `userid` = ?");
            $stmt->bind_param("i", $userId);
            $stmt->execute();
            $stmt->close();
        }

        echo json_encode([
            'status' => 'success',
            'message' => 'اکانت تست با موفقیت صادر شد.',
            'config' => [
                'remark' => $remark,
                'link' => $configLinks[0] ?? $directSubLink,
                'sub_link' => $directSubLink,
                'web_link' => "https://wizwiz.villux.ir:8443/Netfreedom/search.php?id=" . $clientSubId
            ]
        ]);
        break;

    case 'buy_plan':
        $planId = intval($input['plan_id'] ?? 0);
        if ($planId <= 0) {
            echo json_encode(['error' => 'پلن نامعتبر است.']);
            exit;
        }

        // Fetch plan details
        $stmt = $connection->prepare("SELECT * FROM `server_plans` WHERE `id` = ? AND `active` = 1 LIMIT 1");
        $stmt->bind_param("i", $planId);
        $stmt->execute();
        $file_detail = $stmt->get_result()->fetch_assoc();
        $stmt->close();

        if (!$file_detail) {
            echo json_encode(['error' => 'پلن یافت نشد یا غیرفعال است.']);
            exit;
        }

        $price = intval($file_detail['price']);
        if ($userInfo['wallet'] < $price) {
            echo json_encode(['error' => 'موجودی کیف پول شما کافی نیست.']);
            exit;
        }

        $id = $file_detail['id'];
        $days = intval($file_detail['days']);
        $date = time();
        $expire_date = ($days > 0) ? $date + (86400 * $days) : 0;
        $volume = intval($file_detail['volume']);
        $server_id = $file_detail['server_id'];
        $acount = $file_detail['acount'];
        $inbound_id_raw = $file_detail['inbound_id']; 
        $limitip = intval($file_detail['limitip']);
        $rahgozar = $file_detail['rahgozar'];
        $agentBought = false;

        // Check server ucount
        $stmt = $connection->prepare("SELECT * FROM `server_info` WHERE `id` = ?");
        $stmt->bind_param("i", $server_id);
        $stmt->execute();
        $serverInfo = $stmt->get_result()->fetch_assoc();
        $stmt->close();

        if (!$serverInfo || $serverInfo['ucount'] <= 0) {
            echo json_encode(['error' => 'ظرفیت سرور تکمیل شده است.']);
            exit;
        }

        $stmt = $connection->prepare("SELECT * FROM `server_config` WHERE `id` = ?");
        $stmt->bind_param("i", $server_id);
        $stmt->execute();
        $serverConfig = $stmt->get_result()->fetch_assoc();
        $stmt->close();

        if (!$serverConfig) {
            echo json_encode(['error' => 'سرور یافت نشد.']);
            exit;
        }

        $serverType = $serverConfig['type'];
        $panelUrl = rtrim($serverConfig['panel_url'], '/');
        $apiToken = trim($serverConfig['password']); 

        $rnd = rand(1111, 9999);
        $inbound_id_raw_clean = strval($inbound_id_raw);
        $isProxyInbound = (strpos($inbound_id_raw_clean, '7') !== false);
        if ($isProxyInbound) {
            $remark = "Proxy-{$userId}-{$rnd}";
        } else {
            $remark = "User-{$userId}-{$rnd}";
        }
        $finalEmail = $remark . "@tg.com"; 

        $volumeBytes = $volume * 1073741824; 
        $expiryTimestamp = ($days > 0) ? (time() + ($days * 86400)) * 1000 : 0;

        $inboundIdsArray = explode(',', str_replace(['[', ']'], '', $inbound_id_raw));
        $inbound_id_db = intval($inboundIdsArray[0] ?? 1);

        $configLinks = [];
        $clientSubId = ""; 
        $clientUuid = "";

        if ($serverType == "marzban") {
            $response = addMarzbanUser($server_id, $remark, $volume, $days, $id);
            if (is_object($response) && isset($response->sub_link)) {
                $directSubLink = $panelUrl . $response->sub_link;
                $configLinks[] = $directSubLink;
                $clientSubId = $clientUuid = str_replace("/sub/", "", $response->sub_link);
            }
        } else {
            $clientUuid = generateUID();
            $response = addInboundAccount($server_id, $clientUuid, $inbound_id_db, $expiryTimestamp, $remark, $volume, $limitip, null, $id);
            
            if (is_null($response) || !$response->success) {
                echo json_encode(['error' => 'خطا در صدور اکانت از سمت سرور.']);
                exit;
            }
            
            $clientSubId = basename($response->subLink);
            
            $subDecodedObj = callXuiApi($serverConfig, '/panel/api/clients/links/' . urlencode($remark));
            if ($subDecodedObj && isset($subDecodedObj->success) && $subDecodedObj->success && is_array($subDecodedObj->obj)) {
                $configLinks = $subDecodedObj->obj;
            }
        }

        $parsedPanelUrl = parse_url($panelUrl);
        $panelHost = $parsedPanelUrl['host'] ?? '';
        $panelScheme = $parsedPanelUrl['scheme'] ?? 'https';
        $directSubLink = "{$panelScheme}://{$panelHost}:2096/sub/{$clientSubId}";

        $linkForDb = json_encode($configLinks, JSON_UNESCAPED_UNICODE);
        $protocol_placeholder = $file_detail['type'] ?? 'vless';

        // Start transaction manually via queries
        $connection->query("START TRANSACTION");

        // Decrement wallet balance
        $stmt = $connection->prepare("UPDATE `users` SET `wallet` = `wallet` - ? WHERE `userid` = ?");
        $stmt->bind_param("ii", $price, $userId);
        $stmt->execute();
        $stmt->close();

        // Insert order
        $stmt = $connection->prepare("INSERT INTO `orders_list` 
        (`userid`, `token`, `transid`, `fileid`, `server_id`, `inbound_id`, `remark`, `uuid`, `protocol`, `expire_date`, `link`, `amount`, `status`, `date`, `notif`, `rahgozar`, `agent_bought`)
        VALUES (?, ?, '', ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, 0, ?, ?)");

        $stmt->bind_param("isiiisssisiiii", $userId, $clientSubId, $id, $server_id, $inbound_id_db, $remark, $clientSubId, $protocol_placeholder, $expire_date, $linkForDb, $price, $date, $rahgozar, $agentBought);
        $stmt->execute(); 
        $stmt->close();

        // Decrement capacity
        $stmt = $connection->prepare("UPDATE `server_info` SET `ucount` = `ucount` - 1 WHERE `id` = ?");
        $stmt->bind_param("i", $server_id); 
        $stmt->execute(); 
        $stmt->close();

        if ($file_detail['type'] != 'client_centric') {
            $stmt = $connection->prepare("UPDATE `server_plans` SET `acount` = `acount` - 1 WHERE `id` = ?");
            $stmt->bind_param("i", $id); 
            $stmt->execute(); 
            $stmt->close();
        }

        $connection->query("COMMIT");

        echo json_encode([
            'status' => 'success',
            'message' => 'خرید با موفقیت انجام شد.',
            'config' => [
                'remark' => $remark,
                'link' => $configLinks[0] ?? $directSubLink,
                'sub_link' => $directSubLink
            ]
        ]);
        break;

    case 'plans':
        // Get active categories and plans
        $res = $connection->query("SELECT * FROM `server_plans` WHERE `active` = 1 ORDER BY `step` ASC");
        $plans = $res ? $res->fetch_all(MYSQLI_ASSOC) : [];
        
        $resServers = $connection->query("SELECT *, title AS name FROM `server_info` WHERE `active` = 1 AND `state` = 1");
        $servers = $resServers ? $resServers->fetch_all(MYSQLI_ASSOC) : [];

        $resCats = $connection->query("SELECT * FROM `server_categories` ORDER BY `step` ASC");
        $categories = $resCats ? $resCats->fetch_all(MYSQLI_ASSOC) : [];

        echo json_encode([
            'status' => 'success',
            'plans' => $plans,
            'servers' => $servers,
            'categories' => $categories
        ]);
        break;

    case 'tickets':
        if ($isAdmin) {
            // Admin sees ALL tickets with user info
            $tickRes = $connection->query("SELECT c.*, u.name as user_name, u.username as user_username, u.userid as user_tg_id FROM `chats` c LEFT JOIN `users` u ON c.user_id = u.userid ORDER BY c.state ASC, c.id DESC");
            $tickets = $tickRes ? $tickRes->fetch_all(MYSQLI_ASSOC) : [];
            // Add user photo URLs for admin view
            foreach ($tickets as &$ticket) {
                $tPhoto = fetchUserProfilePhoto($ticket['user_tg_id'] ?? $ticket['user_id'], $botToken);
                $ticket['user_photo'] = $tPhoto ? (strpos($tPhoto, 'http') === 0 ? $tPhoto : '../' . $tPhoto) : null;
            }
            unset($ticket);
        } else {
            $tickStmt = $connection->prepare("SELECT * FROM `chats` WHERE `user_id` = ? ORDER BY `id` DESC");
            $tickStmt->bind_param("i", $userId);
            $tickStmt->execute();
            $tickets = $tickStmt->get_result()->fetch_all(MYSQLI_ASSOC);
            $tickStmt->close();
        }

        echo json_encode(['status' => 'success', 'tickets' => $tickets]);
        break;

    case 'ticket_messages':
        $chatId = intval($input['chat_id']);
        
        // Verify ticket ownership (unless admin)
        if (!$isAdmin) {
            $checkStmt = $connection->prepare("SELECT id FROM `chats` WHERE `id` = ? AND `user_id` = ?");
            $checkStmt->bind_param("ii", $chatId, $userId);
            $checkStmt->execute();
            if ($checkStmt->get_result()->num_rows === 0) {
                echo json_encode(['error' => 'دسترسی غیرمجاز به تیکت']);
                exit;
            }
            $checkStmt->close();
        }

        $msgStmt = $connection->prepare("SELECT * FROM `chats_info` WHERE `chat_id` = ? ORDER BY `id` ASC");
        $msgStmt->bind_param("i", $chatId);
        $msgStmt->execute();
        $messages = $msgStmt->get_result()->fetch_all(MYSQLI_ASSOC);
        $msgStmt->close();

        // Fetch ticket owner info for chat avatars
        $chatOwnerStmt = $connection->prepare("SELECT c.user_id, u.name as user_name, u.username as user_username FROM `chats` c LEFT JOIN `users` u ON c.user_id = u.userid WHERE c.id = ?");
        $chatOwnerStmt->bind_param("i", $chatId);
        $chatOwnerStmt->execute();
        $chatOwner = $chatOwnerStmt->get_result()->fetch_assoc();
        $chatOwnerStmt->close();

        $userPhoto = null;
        $adminPhoto = null;
        if ($chatOwner) {
            $userPhoto = fetchUserProfilePhoto($chatOwner['user_id'], $botToken);
            $userPhoto = $userPhoto ? (strpos($userPhoto, 'http') === 0 ? $userPhoto : '../' . $userPhoto) : null;
        }
        // Admin photo (current logged-in admin)
        if ($isAdmin) {
            $adminPhoto = fetchUserProfilePhoto($userId, $botToken);
            $adminPhoto = $adminPhoto ? (strpos($adminPhoto, 'http') === 0 ? $adminPhoto : '../' . $adminPhoto) : null;
        }

        echo json_encode([
            'status' => 'success',
            'messages' => $messages,
            'chat_user' => [
                'name' => $chatOwner['user_name'] ?? 'کاربر',
                'username' => $chatOwner['user_username'] ?? '',
                'photo' => $userPhoto
            ],
            'chat_admin' => [
                'name' => 'پشتیبانی',
                'photo' => $adminPhoto
            ]
        ]);
        break;

    case 'create_ticket':
        $title = mb_substr(trim($_POST['title'] ?? $input['title'] ?? ''), 0, 100);
        $category = trim($_POST['category'] ?? $input['category'] ?? 'بررسی کانفیگ');
        $text = trim($_POST['text'] ?? $input['text'] ?? '');

        if (empty($title)) {
            echo json_encode(['error' => 'موضوع الزامی است']);
            exit;
        }
        if (empty($text) && empty($_FILES['file'])) {
            echo json_encode(['error' => 'متن پیام یا فایل پیوستی الزامی است']);
            exit;
        }

        $now = time();
        $state = 1; // 1 = open / unanswered
        $rate = 0;

        $stmt = $connection->prepare("INSERT INTO `chats` (`user_id`, `create_date`, `title`, `category`, `state`, `rate`) VALUES (?, ?, ?, ?, ?, ?)");
        $stmt->bind_param("iissii", $userId, $now, $title, $category, $state, $rate);
        $stmt->execute();
        $chatId = $stmt->insert_id;
        $stmt->close();

        $fileJson = null;
        if (isset($_FILES['file']) && $_FILES['file']['error'] === UPLOAD_ERR_OK) {
            $file = $_FILES['file'];
            $filePath = $file['tmp_name'];
            $fileName = $file['name'];
            $mime = $file['type'];
            
            $method = 'sendDocument';
            $type = 'document';
            if (strpos($mime, 'image/') === 0) {
                $method = 'sendPhoto';
                $type = 'photo';
            } elseif (strpos($mime, 'video/') === 0) {
                $method = 'sendVideo';
                $type = 'video';
            } elseif (strpos($mime, 'audio/') === 0 || strpos($mime, 'ogg') !== false) {
                $method = 'sendVoice';
                $type = 'voice';
            }
            
            $cfile = new CURLFile($filePath, $mime, $fileName);
            
            // Set caption
            $caption = "📢 <b>تیکت جدید ثبت شد (پیوست‌دار)</b>\n\n" .
                       "👤 <b>کاربر:</b> <a href='tg://user?id={$userId}'>" . htmlspecialchars($userInfo['name'] ?? 'کاربر') . "</a>" . (!empty($userInfo['username']) ? " (@" . htmlspecialchars($userInfo['username']) . ")" : "") . "\n" .
                       "🆔 <b>آیدی عددی:</b> <code>{$userId}</code>\n" .
                       "💬 <b>موضوع:</b> " . htmlspecialchars($title) . "\n" .
                       "📂 <b>دسته‌بندی:</b> " . htmlspecialchars($category) . "\n\n";
            if (!empty($text)) {
                $caption .= "📝 <b>متن پیام:</b>\n" . htmlspecialchars($text);
            }
            
            $kb = json_encode(['inline_keyboard' => [
                [
                    ['text' => '✍️ پاسخ در ربات', 'callback_data' => "reply_{$chatId}"],
                    ['text' => '📱 پاسخ در مینی‌اپ', 'web_app' => ['url' => "https://wizwiz.villux.ir:8443/Netfreedom/mini-app/#tickets-{$chatId}"]]
                ]
            ]]);

            $postFields = [
                'chat_id' => $admin,
                $type => $cfile,
                'caption' => mb_substr($caption, 0, 1024),
                'parse_mode' => 'HTML',
                'reply_markup' => $kb
            ];
            
            $ch = curl_init("https://api.telegram.org/bot" . $botToken . "/" . $method);
            curl_setopt($ch, CURLOPT_POST, 1);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $postFields);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            $res = curl_exec($ch);
            curl_close($ch);
            
            $resDec = json_decode($res, true);
            if ($resDec && isset($resDec['ok']) && $resDec['ok']) {
                $resultObj = $resDec['result'];
                $fileId = '';
                if ($type == 'photo') {
                    $sizes = $resultObj['photo'];
                    $fileId = $sizes[count($sizes) - 1]['file_id'];
                } else {
                    $fileId = $resultObj[$type]['file_id'];
                }
                $fileJson = json_encode([
                    'file_id' => $fileId,
                    'caption' => $text,
                    'file_type' => $type
                ], JSON_UNESCAPED_UNICODE);
            }
        }

        $msgTextVal = $fileJson ? $fileJson : $text;
        $msgType = 'text';
        $stmtMsg = $connection->prepare("INSERT INTO `chats_info` (`chat_id`, `sent_date`, `msg_type`, `text`) VALUES (?, ?, ?, ?)");
        $stmtMsg->bind_param("iiss", $chatId, $now, $msgType, $msgTextVal);
        $stmtMsg->execute();
        $stmtMsg->close();

        // If it was a plain text ticket, notify admin by text
        if (!$fileJson) {
            $msgText = "📢 <b>تیکت جدید ثبت شد</b>\n\n" .
                       "👤 <b>کاربر:</b> <a href='tg://user?id={$userId}'>" . htmlspecialchars($userInfo['name'] ?? 'کاربر') . "</a>" . (!empty($userInfo['username']) ? " (@" . htmlspecialchars($userInfo['username']) . ")" : "") . "\n" .
                       "🆔 <b>آیدی عددی:</b> <code>{$userId}</code>\n" .
                       "💬 <b>موضوع:</b> " . htmlspecialchars($title) . "\n" .
                       "📂 <b>دسته‌بندی:</b> " . htmlspecialchars($category) . "\n\n" .
                       "📝 <b>متن پیام:</b>\n" . htmlspecialchars($text);
            
            $kb = json_encode(['inline_keyboard' => [
                [
                    ['text' => '✍️ پاسخ در ربات', 'callback_data' => "reply_{$chatId}"],
                    ['text' => '📱 پاسخ در مینی‌اپ', 'web_app' => ['url' => "https://wizwiz.villux.ir:8443/Netfreedom/mini-app/#tickets-{$chatId}"]]
                ]
            ]]);
            sendMessage($msgText, $kb, "HTML", $admin);
        }

        echo json_encode(['status' => 'success', 'chat_id' => $chatId]);
        break;

    case 'send_ticket_reply':
        $chatId = intval($input['chat_id']);
        $text = trim($input['text'] ?? '');

        if (empty($text)) {
            echo json_encode(['error' => 'متن پیام خالی است']);
            exit;
        }

        // Validate ticket ownership / admin role
        if (!$isAdmin) {
            $checkStmt = $connection->prepare("SELECT id FROM `chats` WHERE `id` = ? AND `user_id` = ?");
            $checkStmt->bind_param("ii", $chatId, $userId);
            $checkStmt->execute();
            if ($checkStmt->get_result()->num_rows === 0) {
                echo json_encode(['error' => 'دسترسی غیرمجاز']);
                exit;
            }
            $checkStmt->close();
        }

        $now = time();
        $msgType = $isAdmin ? 'admin' : 'text';
        $replyToId = isset($input['reply_to_id']) && intval($input['reply_to_id']) > 0 ? intval($input['reply_to_id']) : null;

        // Insert reply
        $stmt = $connection->prepare("INSERT INTO `chats_info` (`chat_id`, `sent_date`, `msg_type`, `text`, `reply_to_id`) VALUES (?, ?, ?, ?, ?)");
        $stmt->bind_param("iissi", $chatId, $now, $msgType, $text, $replyToId);
        $stmt->execute();
        $stmt->close();

        // Update ticket state: if admin replied, set state to answered (1). If user replied, set to open (0).
        $newState = $isAdmin ? 1 : 0;
        $upStmt = $connection->prepare("UPDATE `chats` SET `state` = ? WHERE `id` = ?");
        $upStmt->bind_param("ii", $newState, $chatId);
        $upStmt->execute();
        $upStmt->close();

        // Notify user if admin replied
        if ($isAdmin) {
            $tStmt = $connection->prepare("SELECT * FROM `chats` WHERE `id` = ?");
            if ($tStmt) {
                $tStmt->bind_param("i", $chatId);
                $tStmt->execute();
                $ticketInfo = $tStmt->get_result()->fetch_assoc();
                $tStmt->close();

                if ($ticketInfo) {
                    $targetUserId = $ticketInfo['user_id'];
                    $ticketTitle = $ticketInfo['title'];
                    $ticketCat = $ticketInfo['category'];

                    $msgText = "💌 <b>تیکت شما توسط پشتیبانی پاسخ داده شد 😍</b>\n\n" .
                               "💬 <b>موضوع تیکت:</b> " . htmlspecialchars($ticketTitle) . "\n" .
                               "📂 <b>دسته‌بندی:</b> " . htmlspecialchars($ticketCat) . "\n\n" .
                               "✍️ <b>پاسخ ادمین:</b>\n" .
                               "<blockquote><i>" . htmlspecialchars($text) . "</i></blockquote>";
                    
                    $keyboard = json_encode(['inline_keyboard' => [
                        [
                            ['text' => 'پاسخ در ربات 📝', 'callback_data' => "replySupport_{$chatId}"],
                            ['text' => 'ادامه در مینی‌اپ 📱', 'web_app' => ['url' => "https://wizwiz.villux.ir:8443/Netfreedom/mini-app/#tickets-{$chatId}"]]
                        ],
                        [
                            ['text' => "بستن تیکت 🗳", 'callback_data' => "closeTicket_$chatId"]
                        ]
                    ]]);

                    sendMessage($msgText, $keyboard, "HTML", $targetUserId);
                }
            }
        }

        echo json_encode(['status' => 'success']);
        break;

    case 'send_ticket_reply_file':
        $chatId = intval($_POST['chat_id'] ?? 0);
        $caption = trim($_POST['caption'] ?? '');
        
        if (empty($_FILES['file'])) {
            echo json_encode(['error' => 'فایلی یافت نشد.']);
            exit;
        }
        
        // Find ticket info
        $tStmt = $connection->prepare("SELECT * FROM `chats` WHERE `id` = ?");
        $tStmt->bind_param("i", $chatId);
        $tStmt->execute();
        $ticketInfo = $tStmt->get_result()->fetch_assoc();
        $tStmt->close();
        
        if (!$ticketInfo) {
            echo json_encode(['error' => 'تیکت یافت نشد.']);
            exit;
        }
        
        $targetUserId = $ticketInfo['user_id'];
        $ticketTitle = $ticketInfo['title'];
        $ticketCat = $ticketInfo['category'];
        
        // Upload file to Telegram
        $file = $_FILES['file'];
        $filePath = $file['tmp_name'];
        $fileName = $file['name'];
        $mime = $file['type'];
        
        // Determine Telegram send type based on MIME
        $method = 'sendDocument';
        $type = 'document';
        if (strpos($mime, 'image/') === 0) {
            $method = 'sendPhoto';
            $type = 'photo';
        } elseif (strpos($mime, 'video/') === 0) {
            $method = 'sendVideo';
            $type = 'video';
        } elseif (strpos($mime, 'audio/') === 0 || strpos($mime, 'ogg') !== false) {
            $method = 'sendVoice';
            $type = 'voice';
        }
        
        // Prepare curl request to Telegram
        $cfile = new CURLFile($filePath, $mime, $fileName);
        $recipientId = $isAdmin ? $targetUserId : $admin;
        
        $postFields = [
            'chat_id' => $recipientId,
            $type => $cfile
        ];
        
        if (!empty($caption)) {
            $postFields['caption'] = $caption;
        }
        
        // Set markup if admin replied, so user gets the action buttons
        if ($isAdmin) {
            $postFields['caption'] = "💌 <b>تیکت شما توسط پشتیبانی پاسخ داده شد 😍</b>\n\n" .
                                     "💬 <b>موضوع تیکت:</b> " . htmlspecialchars($ticketTitle) . "\n" .
                                     "📂 <b>دسته‌بندی:</b> " . htmlspecialchars($ticketCat) . "\n\n" .
                                     "✍️ <b>پاسخ ادمین:</b>\n" .
                                     "<blockquote><i>" . htmlspecialchars($caption) . "</i></blockquote>";
            $postFields['reply_markup'] = json_encode(['inline_keyboard' => [
                [
                    ['text' => 'پاسخ در ربات 📝', 'callback_data' => "replySupport_{$chatId}"],
                    ['text' => 'ادامه در مینی‌اپ 📱', 'web_app' => ['url' => "https://wizwiz.villux.ir:8443/Netfreedom/mini-app/#tickets-{$chatId}"]]
                ],
                [
                    ['text' => "بستن تیکت 🗳", 'callback_data' => "closeTicket_$chatId"]
                ]
            ]]);
            $postFields['parse_mode'] = 'HTML';
        }
        
        $ch = curl_init("https://api.telegram.org/bot" . $botToken . "/" . $method);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $postFields);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        $res = curl_exec($ch);
        curl_close($ch);
        
        $resDec = json_decode($res, true);
        
        if ($resDec && isset($resDec['ok']) && $resDec['ok']) {
            $resultObj = $resDec['result'];
            $fileId = '';
            
            if ($type == 'photo') {
                $sizes = $resultObj['photo'];
                $fileId = $sizes[count($sizes) - 1]['file_id'];
            } else {
                $fileId = $resultObj[$type]['file_id'];
            }
            
            $now = time();
            $msgType = $isAdmin ? 'admin' : 'text';
            $fileJson = json_encode([
                'file_id' => $fileId,
                'caption' => $caption,
                'file_type' => $type
            ], JSON_UNESCAPED_UNICODE);
            
            $replyToId = isset($_POST['reply_to_id']) && intval($_POST['reply_to_id']) > 0 ? intval($_POST['reply_to_id']) : null;

            $stmt = $connection->prepare("INSERT INTO `chats_info` (`chat_id`, `sent_date`, `msg_type`, `text`, `reply_to_id`) VALUES (?, ?, ?, ?, ?)");
            $stmt->bind_param("iissi", $chatId, $now, $msgType, $fileJson, $replyToId);
            $stmt->execute();
            $stmt->close();
            
            $newState = $isAdmin ? 1 : 0;
            $upStmt = $connection->prepare("UPDATE `chats` SET `state` = ? WHERE `id` = ?");
            $upStmt->bind_param("ii", $newState, $chatId);
            $upStmt->execute();
            $upStmt->close();
            
            echo json_encode(['status' => 'success']);
        } else {
            echo json_encode(['error' => 'خطا در آپلود فایل به تلگرام: ' . ($resDec['description'] ?? 'unknown')]);
        }
        break;

    case 'send_file_to_telegram':
        $fileId = trim($input['file_id'] ?? '');
        $fileType = trim($input['file_type'] ?? 'document');
        $caption = trim($input['caption'] ?? '');
        
        if (empty($fileId)) {
            echo json_encode(['error' => 'شناسه فایل نامعتبر است.']);
            exit;
        }
        
        if ($fileType == 'photo') {
            bot('sendPhoto', ['chat_id' => $userId, 'photo' => $fileId, 'caption' => $caption]);
        } elseif ($fileType == 'video') {
            bot('sendVideo', ['chat_id' => $userId, 'video' => $fileId, 'caption' => $caption]);
        } elseif ($fileType == 'voice' || $fileType == 'audio') {
            bot('sendVoice', ['chat_id' => $userId, 'voice' => $fileId, 'caption' => $caption]);
        } else {
            bot('sendDocument', ['chat_id' => $userId, 'document' => $fileId, 'caption' => $caption]);
        }
        
        echo json_encode(['status' => 'success', 'message' => 'فایل با موفقیت به تلگرام شما ارسال شد.']);
        break;

    case 'send_npvt':
        $configId = intval($input['config_id'] ?? 0);
        if ($configId <= 0) {
            echo json_encode(['error' => 'شناسه کانفیگ نامعتبر است.']);
            exit;
        }

        $stmt = $connection->prepare("SELECT * FROM `orders_list` WHERE `id` = ? AND `userid` = ?");
        $stmt->bind_param("ii", $configId, $userId);
        $stmt->execute();
        $order = $stmt->get_result()->fetch_assoc();
        $stmt->close();

        if (!$order) {
            echo json_encode(['error' => 'کانفیگ یافت نشد.']);
            exit;
        }

        $remark = $order['remark'];
        $linksJson = $order['link'] ?? '';
        $linksArray = json_decode($linksJson, true);
        if (!is_array($linksArray) || empty($linksArray)) {
            $linksArray = !empty($linksJson) ? [$linksJson] : [];
        }

        $botUrl = 'https://wizwiz.villux.ir:8443/Netfreedom/';
        $subLink = !empty($order['token']) ? $botUrl . "sub/" . $order['token'] : null;

        sendNpvtDocument($linksArray, $remark, $userId, $subLink);

        echo json_encode(['status' => 'success', 'message' => 'فایل .npvt با موفقیت در چت تلگرام برای شما ارسال شد.']);
        break;

    case 'close_ticket':
        $chatId = intval($input['chat_id']);
        $rate = intval($input['rate'] ?? 5);
        if ($rate < 1) $rate = 1;
        if ($rate > 5) $rate = 5;

        // Verify ticket ownership (unless admin)
        if (!$isAdmin) {
            $checkStmt = $connection->prepare("SELECT id FROM `chats` WHERE `id` = ? AND `user_id` = ?");
            $checkStmt->bind_param("ii", $chatId, $userId);
            $checkStmt->execute();
            if ($checkStmt->get_result()->num_rows === 0) {
                echo json_encode(['error' => 'دسترسی غیرمجاز به تیکت']);
                exit;
            }
            $checkStmt->close();
        }

        $upStmt = $connection->prepare("UPDATE `chats` SET `state` = 2, `rate` = ? WHERE `id` = ?");
        $upStmt->bind_param("ii", $rate, $chatId);
        $upStmt->execute();
        $upStmt->close();

        // Also add a message in the chat info about the closure
        $now = time();
        $msgType = 'text';
        $closureMsg = "🔒 تیکت توسط کاربر بسته شد. امتیاز ثبت شده: " . str_repeat('⭐', $rate);
        $stmtMsg = $connection->prepare("INSERT INTO `chats_info` (`chat_id`, `sent_date`, `msg_type`, `text`) VALUES (?, ?, ?, ?)");
        $stmtMsg->bind_param("iiss", $chatId, $now, $msgType, $closureMsg);
        $stmtMsg->execute();
        $stmtMsg->close();

        echo json_encode(['status' => 'success']);
        break;

    case 'wallet_history':
        $payStmt = $connection->prepare("SELECT * FROM `pays` WHERE `user_id` = ? ORDER BY `id` DESC LIMIT 20");
        $payStmt->bind_param("i", $userId);
        $payStmt->execute();
        $rows = $payStmt->get_result()->fetch_all(MYSQLI_ASSOC);
        $payStmt->close();

        echo json_encode(['status' => 'success', 'history' => $rows]);
        break;

    case 'submit_receipt':
        $amount = intval($_POST['amount'] ?? $_GET['amount'] ?? $input['amount'] ?? 0);
        $fileid = '';

        if ($amount <= 0) {
            echo json_encode(['error' => 'مبلغ الزامی است']);
            exit;
        }

        $hashId = uniqid('pay_');
        $desc = "افزایش موجودی کیف پول - مینی اپ";
        $now = time();
        $state = 'pending';
        $type = 'INCREASE_WALLET';
        $amountRial = $amount;

        // Send to admin using the bot's template message
        $msg = str_replace(['PRICE', 'USERNAME', 'NAME', 'USER-ID'], [number_format($amount), $userInfo['username'] ?? 'ندارد', $userInfo['name'] ?? 'کاربر', $userId], $mainValues['increase_wallet_request_message']);

        $keyboard = json_encode([
            'inline_keyboard' => [
                [
                    [
                        'text' => $buttonValues['approve'] ?? 'تایید', 
                        'callback_data' => "approvePayment" . $hashId,
                        'style' => 'success',
                        'icon_custom_emoji_id' => '5208880351690112495'
                    ],
                    [
                        'text' => $buttonValues['decline'] ?? 'رد کردن', 
                        'callback_data' => "decPayment" . $hashId,
                        'style' => 'danger',
                        'icon_custom_emoji_id' => '5215680783863261658'
                    ]
                ]
            ]
        ]);

        if (isset($_FILES['receipt']) && $_FILES['receipt']['error'] === UPLOAD_ERR_OK) {
            $fileid = uploadFileToTelegram($_FILES['receipt'], $botToken, $admin, $msg, $keyboard, "HTML");
        } else {
            echo json_encode(['error' => 'آپلود تصویر رسید الزامی است']);
            exit;
        }

        if (empty($fileid)) {
            echo json_encode(['error' => 'خطا در ارسال تصویر رسید به تلگرام']);
            exit;
        }

        $stmt = $connection->prepare("INSERT INTO `pays` (`hash_id`, `description`, `payid`, `user_id`, `type`, `price`, `request_date`, `state`) VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
        $stmt->bind_param("sssiisss", $hashId, $desc, $fileid, $userId, $type, $amountRial, $now, $state);
        $stmt->execute();
        $stmt->close();

        echo json_encode(['status' => 'success', 'message' => 'رسید با موفقیت ارسال شد و در انتظار تایید مدیریت است.']);
        break;

    case 'submit_plan_receipt':
        $planId = intval($_POST['plan_id'] ?? $_GET['plan_id'] ?? $input['plan_id'] ?? 0);
        $remark = trim($_POST['remark'] ?? $_GET['remark'] ?? $input['remark'] ?? '');
        $fileid = '';

        if ($planId <= 0) {
            echo json_encode(['error' => 'شناسه پلن معتبر نیست']);
            exit;
        }

        // Fetch plan details
        $stmt = $connection->prepare("SELECT * FROM `server_plans` WHERE `id` = ?");
        $stmt->bind_param("i", $planId);
        $stmt->execute();
        $planInfo = $stmt->get_result()->fetch_assoc();
        $stmt->close();

        if (!$planInfo) {
            echo json_encode(['error' => 'پلن مورد نظر یافت نشد']);
            exit;
        }

        // Fetch category name
        $stmt = $connection->prepare("SELECT `title` FROM `server_categories` WHERE `id` = ?");
        $stmt->bind_param("i", $planInfo['catid']);
        $stmt->execute();
        $catname = $stmt->get_result()->fetch_assoc()['title'] ?? 'عمومی';
        $stmt->close();

        $plan_title = $catname . " " . $planInfo['title'];
        $planPrice = intval($planInfo['price']); // in Rial!
        $volumeTxt = ($planInfo['volume'] == 0) ? "نامحدود" : $planInfo['volume'] . " گیگ";
        $daysTxt = ($planInfo['days'] == 0) ? "نامحدود" : $planInfo['days'] . " روز";
        $ipLimitTxt = ($planInfo['limitip'] == 0) ? "بدون محدودیت" : $planInfo['limitip'] . " کاربره";

        if (empty($remark)) {
            $remark = $plan_title . " (تولید خودکار)";
        }

        $hashId = uniqid('pay_');
        $desc = $remark;
        $now = time();
        $state = 'pending';
        $type = 'BUY_SUB';

        // Construct admin confirmation caption exactly like payments.php
        $msgAdmin = "📥 <b>رسید جدید (کارت به کارت)</b>\n\n" .
                    "👤 خریدار: <a href='tg://user?id={$userId}'>{$userInfo['name']}</a>\n" .
                    "🆔 آیدی عددی: <code>{$userId}</code>\n" .
                    "💬 یوزرنیم: @{$userInfo['username']}\n" .
                    "💵 مبلغ پرداختی: <code>" . number_format($planPrice) . " تومان</code>\n" .
                    "---------------------------------------\n" .
                    "🔮 پلن انتخابی: <code>{$plan_title}</code>\n" .
                    "✏️ نام سرویس: <code>{$remark}</code>\n" .
                    "🔋 حجم سرویس: <code>{$volumeTxt}</code>\n" .
                    "⏰ مدت سرویس: <code>{$daysTxt}</code>\n" .
                    "👥 کاربر مجاز: <code>{$ipLimitTxt}</code>";

        $keyboard = json_encode([
            'inline_keyboard' => [
                [
                    [
                        'text' => "تایید",
                        'callback_data' => "accCustom" . $hashId,
                        'style' => 'success',
                        'icon_custom_emoji_id' => '5208880351690112495'
                    ],
                    [
                        'text' => "عدم تایید",
                        'callback_data' => "decline" . $userId . "_" . $hashId,
                        'style' => 'danger',
                        'icon_custom_emoji_id' => '5215680783863261658'
                    ]
                ]
            ]
        ]);

        if (isset($_FILES['receipt']) && $_FILES['receipt']['error'] === UPLOAD_ERR_OK) {
            $fileid = uploadFileToTelegram($_FILES['receipt'], $botToken, $admin, $msgAdmin, $keyboard, "HTML");
        } else {
            echo json_encode(['error' => 'آپلود تصویر رسید الزامی است']);
            exit;
        }

        if (empty($fileid)) {
            echo json_encode(['error' => 'خطا در ارسال تصویر رسید به تلگرام']);
            exit;
        }

        // Insert pending transaction in pays table
        $stmt = $connection->prepare("INSERT INTO `pays` (`hash_id`, `description`, `payid`, `user_id`, `type`, `price`, `request_date`, `state`, `plan_id`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)");
        $stmt->bind_param("sssiisssi", $hashId, $desc, $fileid, $userId, $type, $planPrice, $now, $state, $planId);
        $stmt->execute();
        $stmt->close();

        echo json_encode(['status' => 'success', 'message' => 'رسید با موفقیت ارسال شد و در انتظار تایید مدیریت است.']);
        break;

    case 'delete_config':
        $id = intval($input['id'] ?? 0);
        if ($id <= 0) {
            echo json_encode(['error' => 'شناسه نامعتبر است.']);
            exit;
        }

        $stmt = $connection->prepare("SELECT * FROM `orders_list` WHERE `id` = ? AND `userid` = ?");
        $stmt->bind_param("ii", $id, $userId);
        $stmt->execute();
        $orderInfo = $stmt->get_result()->fetch_assoc();
        $stmt->close();

        if (!$orderInfo) {
            echo json_encode(['error' => 'سرویس مورد نظر یافت نشد.']);
            exit;
        }

        $server_id = intval($orderInfo['server_id']);
        $inbound_id = intval($orderInfo['inbound_id']);
        $uuid = $orderInfo['uuid'];
        $remark = $orderInfo['remark'];

        $stmt = $connection->prepare("SELECT * FROM `server_info` WHERE `id` = ?");
        $stmt->bind_param("i", $server_id);
        $stmt->execute();
        $serverInfo = $stmt->get_result()->fetch_assoc();
        $stmt->close();

        if ($serverInfo) {
            $isMarzban = ($serverInfo['type'] == 'marzban');
            if ($isMarzban) {
                deleteMarzban($server_id, $remark);
            } else {
                if ($inbound_id > 0) {
                    deleteClient($server_id, $inbound_id, $uuid, 1);
                } else {
                    deleteInbound($server_id, $uuid, 1);
                }
            }
        }

        $stmt = $connection->prepare("DELETE FROM `orders_list` WHERE `id` = ?");
        $stmt->bind_param("i", $id);
        $stmt->execute();
        $stmt->close();

        echo json_encode(['status' => 'success', 'message' => 'سرویس شما با موفقیت حذف گردید.']);
        break;

    case 'renew_config_wallet':
        $configId = intval($input['config_id'] ?? 0);
        $planId = intval($input['plan_id'] ?? 0);

        if ($configId <= 0 || $planId <= 0) {
            echo json_encode(['error' => 'اطلاعات ارسالی نامعتبر است.']);
            exit;
        }

        $stmt = $connection->prepare("SELECT * FROM `orders_list` WHERE `id` = ? AND `userid` = ?");
        $stmt->bind_param("ii", $configId, $userId);
        $stmt->execute();
        $orderInfo = $stmt->get_result()->fetch_assoc();
        $stmt->close();

        if (!$orderInfo) {
            echo json_encode(['error' => 'سرویس یافت نشد.']);
            exit;
        }

        $stmt = $connection->prepare("SELECT * FROM `server_plans` WHERE `id` = ?");
        $stmt->bind_param("i", $planId);
        $stmt->execute();
        $planInfo = $stmt->get_result()->fetch_assoc();
        $stmt->close();

        if (!$planInfo) {
            echo json_encode(['error' => 'پلن یافت نشد.']);
            exit;
        }

        $price = intval($planInfo['price']);
        if ($userInfo['wallet'] < $price) {
            echo json_encode(['error' => 'موجودی کیف پول شما کافی نیست.']);
            exit;
        }

        $newWallet = $userInfo['wallet'] - $price;
        $upStmt = $connection->prepare("UPDATE `users` SET `wallet` = ? WHERE `userid` = ?");
        $upStmt->bind_param("ii", $newWallet, $userId);
        $upStmt->execute();
        $upStmt->close();

        $server_id = intval($orderInfo['server_id']);
        $inbound_id = intval($orderInfo['inbound_id']);
        $uuid = $orderInfo['uuid'];
        $remark = $orderInfo['remark'];
        $plan_vol = floatval($planInfo['volume']);
        $days = intval($planInfo['days']);

        $stmt = $connection->prepare("SELECT * FROM `server_info` WHERE `id` = ?");
        $stmt->bind_param("i", $server_id);
        $stmt->execute();
        $serverInfo = $stmt->get_result()->fetch_assoc();
        $stmt->close();

        if ($serverInfo) {
            $isMarzban = ($serverInfo['type'] == 'marzban');
            if ($isMarzban) {
                renewMarzbanUUID($server_id, $remark);
            } else {
                if ($inbound_id > 0) {
                    editClientTraffic($server_id, $inbound_id, $uuid, $plan_vol, $days, "renew");
                } else {
                    editInboundTraffic($server_id, $uuid, $plan_vol, $days, "renew");
                }
            }
        }

        $currentExpire = intval($orderInfo['expire_date']);
        $baseTime = ($currentExpire > time()) ? $currentExpire : time();
        $newExpiry = $baseTime + ($days * 86400);

        $stmt = $connection->prepare("UPDATE `orders_list` SET `expire_date` = ?, `status` = 1, `notif` = 0 WHERE `id` = ?");
        $stmt->bind_param("ii", $newExpiry, $configId);
        $stmt->execute();
        $stmt->close();

        echo json_encode(['status' => 'success', 'message' => 'اشتراک شما با موفقیت تمدید شد.']);
        break;

    case 'renew_config_agent':
        $configId = intval($input['config_id'] ?? 0);
        $planId = intval($input['plan_id'] ?? 0);

        if ($configId <= 0 || $planId <= 0) {
            echo json_encode(['error' => 'اطلاعات ارسالی نامعتبر است.']);
            exit;
        }

        if (empty($userInfo['is_agent']) && empty($userInfo['isAdmin'])) {
            echo json_encode(['error' => 'شما دسترسی نمایندگی ندارید.']);
            exit;
        }

        $stmt = $connection->prepare("SELECT * FROM `orders_list` WHERE `id` = ? AND `userid` = ?");
        $stmt->bind_param("ii", $configId, $userId);
        $stmt->execute();
        $orderInfo = $stmt->get_result()->fetch_assoc();
        $stmt->close();

        if (!$orderInfo) {
            echo json_encode(['error' => 'سرویس یافت نشد.']);
            exit;
        }

        $stmt = $connection->prepare("SELECT * FROM `server_plans` WHERE `id` = ?");
        $stmt->bind_param("i", $planId);
        $stmt->execute();
        $planInfo = $stmt->get_result()->fetch_assoc();
        $stmt->close();

        if (!$planInfo) {
            echo json_encode(['error' => 'پلن یافت نشد.']);
            exit;
        }

        $plan_vol = floatval($planInfo['volume']);
        $days = intval($planInfo['days']);

        $agentVol = floatval($userInfo['agent_volume'] ?? 0);
        if ($agentVol > 0 && $agentVol < $plan_vol) {
            echo json_encode(['error' => 'حجم کل نمایندگی شما کافی نیست.']);
            exit;
        }

        // کسر حجم از نمایندگی (اگر agent_volume > 0 باشد)
        if ($agentVol > 0) {
            $stmt = $connection->prepare("UPDATE `users` SET `agent_volume` = GREATEST(0, `agent_volume` - ?) WHERE `userid` = ?");
            $stmt->bind_param("di", $plan_vol, $userId);
            $stmt->execute();
            $stmt->close();
        }

        $server_id = intval($orderInfo['server_id']);
        $inbound_id = intval($orderInfo['inbound_id']);
        $uuid = $orderInfo['uuid'];
        $remark = $orderInfo['remark'];

        $stmt = $connection->prepare("SELECT * FROM `server_info` WHERE `id` = ?");
        $stmt->bind_param("i", $server_id);
        $stmt->execute();
        $serverInfo = $stmt->get_result()->fetch_assoc();
        $stmt->close();

        if ($serverInfo) {
            $isMarzban = ($serverInfo['type'] == 'marzban');
            if ($isMarzban) {
                renewMarzbanUUID($server_id, $remark);
            } else {
                if ($inbound_id > 0) {
                    editClientTraffic($server_id, $inbound_id, $uuid, $plan_vol, $days, "renew");
                } else {
                    editInboundTraffic($server_id, $uuid, $plan_vol, $days, "renew");
                }
            }
        }

        $currentExpire = intval($orderInfo['expire_date']);
        $baseTime = ($currentExpire > time()) ? $currentExpire : time();
        $newExpiry = $baseTime + ($days * 86400);

        $stmt = $connection->prepare("UPDATE `orders_list` SET `expire_date` = ?, `status` = 1, `notif` = 0 WHERE `id` = ?");
        $stmt->bind_param("ii", $newExpiry, $configId);
        $stmt->execute();
        $stmt->close();

        echo json_encode(['status' => 'success', 'message' => 'اشتراک شما با موفقیت از حجم نمایندگی تمدید شد.']);
        break;

    case 'renew_config_receipt':
        $configId = intval($_POST['config_id'] ?? $_GET['config_id'] ?? $input['config_id'] ?? 0);
        $planId = intval($_POST['plan_id'] ?? $_GET['plan_id'] ?? $input['plan_id'] ?? 0);
        $fileid = '';

        if ($configId <= 0 || $planId <= 0) {
            echo json_encode(['error' => 'اطلاعات ارسالی نامعتبر است.']);
            exit;
        }

        $stmt = $connection->prepare("SELECT * FROM `orders_list` WHERE `id` = ? AND `userid` = ?");
        $stmt->bind_param("ii", $configId, $userId);
        $stmt->execute();
        $orderInfo = $stmt->get_result()->fetch_assoc();
        $stmt->close();

        if (!$orderInfo) {
            echo json_encode(['error' => 'سرویس یافت نشد.']);
            exit;
        }

        $stmt = $connection->prepare("SELECT * FROM `server_plans` WHERE `id` = ?");
        $stmt->bind_param("i", $planId);
        $stmt->execute();
        $planInfo = $stmt->get_result()->fetch_assoc();
        $stmt->close();

        if (!$planInfo) {
            echo json_encode(['error' => 'پلن یافت نشد.']);
            exit;
        }

        $hashId = uniqid('pay_');
        $desc = json_encode([
            'uuid' => $orderInfo['uuid'],
            'remark' => $orderInfo['remark'],
            'marzban' => ($orderInfo['inbound_id'] == 0)
        ]);
        $now = time();
        $state = 'pending';
        $type = 'RENEW_SCONFIG';
        $price = intval($planInfo['price']);

        $plan_title = $planInfo['title'];
        $daysTxt = $planInfo['days'] . " روز";
        $volumeTxt = $planInfo['volume'] . " گیگ";

        $msg = "♻️ <b>درخواست تمدید سرویس (کارت به کارت)</b>\n\n" .
               "👤 خریدار: <a href='tg://user?id={$userId}'>{$userInfo['name']}</a>\n" .
               "🆔 آیدی عددی: <code>{$userId}</code>\n" .
               "💬 یوزرنیم: @{$userInfo['username']}\n" .
               "💵 مبلغ پرداختی: <code>" . number_format($price) . " تومان</code>\n" .
               "---------------------------------------\n" .
               "🔮 پلن تمدید: <code>{$plan_title}</code>\n" .
               "✏️ نام سرویس: <code>{$orderInfo['remark']}</code>\n" .
               "🔋 حجم سرویس: <code>{$volumeTxt}</code>\n" .
               "⏰ مدت سرویس: <code>{$daysTxt}</code>";

        $keyboard = json_encode([
            'inline_keyboard' => [
                [
                    [
                        'text' => 'تایید', 
                        'callback_data' => 'approveRenewAcc' . $hashId,
                        'style' => 'success',
                        'icon_custom_emoji_id' => '5208880351690112495'
                    ],
                    [
                        'text' => 'رد کردن', 
                        'callback_data' => 'decRenewAcc' . $hashId,
                        'style' => 'danger',
                        'icon_custom_emoji_id' => '5215680783863261658'
                    ]
                ]
            ]
        ]);

        if (isset($_FILES['receipt']) && $_FILES['receipt']['error'] === UPLOAD_ERR_OK) {
            $fileid = uploadFileToTelegram($_FILES['receipt'], $botToken, $admin, $msg, $keyboard, "HTML");
        } else {
            echo json_encode(['error' => 'آپلود تصویر رسید الزامی است.']);
            exit;
        }

        if (empty($fileid)) {
            echo json_encode(['error' => 'خطا در آپلود فیش به تلگرام.']);
            exit;
        }

        $stmt = $connection->prepare("INSERT INTO `pays` (`hash_id`, `description`, `payid`, `user_id`, `type`, `price`, `request_date`, `state`, `plan_id`, `volume`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
        $stmt->bind_param("sssiisssii", $hashId, $desc, $fileid, $userId, $type, $price, $now, $state, $configId, $planId);
        $stmt->execute();
        $stmt->close();

        echo json_encode(['status' => 'success', 'message' => 'رسید تمدید با موفقیت ارسال شد و در انتظار تایید مدیریت است.']);
        break;

    case 'sync_profile':
        $newName = trim($input['name'] ?? '');
        $newPhone = trim($input['phone'] ?? '');

        if (!empty($newName) || !empty($newPhone)) {
            $upStmt = $connection->prepare("UPDATE `users` SET `name` = ?, `phone` = ? WHERE `userid` = ?");
            $upStmt->bind_param("ssi", $newName, $newPhone, $userId);
            $upStmt->execute();
            $upStmt->close();
        }
        echo json_encode(['status' => 'success']);
        break;

    case 'request_agency':
        if ($isAgent) {
            echo json_encode(['error' => 'حساب شما هم‌اکنون به عنوان نماینده فعال است.']);
            exit;
        }

        // Set user is_agent status to 2 (requested)
        $stmt = $connection->prepare("UPDATE `users` SET `is_agent` = 2 WHERE `userid` = ?");
        $stmt->bind_param("i", $userId);
        $stmt->execute();
        $stmt->close();

        // Notify admin via Telegram using sendMessage()
        $msg = str_replace(["USERNAME", "NAME", "USERID"], [$userInfo['username'] ?? 'بدون یوزرنیم', $userInfo['name'] ?? 'کاربر', $userId], $mainValues['request_agency_message']);
        
        $keyboard = json_encode(['inline_keyboard' => [
            [
                [
                    'text' => "تایید", 
                    'callback_data' => "agencyApprove" . $userId,
                    'style' => 'success',
                    'icon_custom_emoji_id' => '5208880351690112495'
                ],
                [
                    'text' => "رد کردن", 
                    'callback_data' => "agencyDecline" . $userId,
                    'style' => 'danger',
                    'icon_custom_emoji_id' => '5215680783863261658'
                ]
            ]
        ]]);
        
        sendMessage($msg, $keyboard, "HTML", $admin);

        echo json_encode(['status' => 'success', 'message' => $mainValues['agency_request_sent']]);
        break;

    // ----------------------------------------------------
    // RESELLER / AGENT ACTIONS
    // ----------------------------------------------------
    case 'agent_dashboard':
        if (!$isAgent && !$isAdmin) {
            echo json_encode(['error' => 'دسترسی غیرمجاز به بخش نمایندگان']);
            exit;
        }

        // Fetch client configurations bought by this reseller (for agents) or ALL configs (for admin)
        if ($isAdmin && !$isAgent) {
            // Admin: fetch all agent-bought configs across all agents
            $clientStmt = $connection->prepare("SELECT o.*, u.name as agent_name, u.username as agent_username FROM `orders_list` o LEFT JOIN `users` u ON o.userid = u.userid WHERE o.agent_bought = 1 ORDER BY o.id DESC");
            $clientStmt->execute();
        } else {
            $clientStmt = $connection->prepare("SELECT * FROM `orders_list` WHERE `userid` = ? AND `agent_bought` = 1 ORDER BY `id` DESC");
            $clientStmt->bind_param("i", $userId);
            $clientStmt->execute();
        }
        $clients = $clientStmt->get_result()->fetch_all(MYSQLI_ASSOC);
        $clientStmt->close();

        $enrichedClients = [];
        foreach ($clients as $client) {
            $stats = fetchSubscriptionRealTimeStats($connection, intval($client['server_id']), $client['remark'], $client['uuid'], $client['token']);
            if ($stats) {
                $client['stats'] = $stats;
            } else {
                $client['stats'] = [
                    'total' => 0,
                    'used' => 0,
                    'remaining' => 0,
                    'expiry_time' => intval($client['expire_date']),
                    'expiry_days' => intval($client['expire_date']) > 0 ? max(0, floor((intval($client['expire_date']) - time()) / 86400)) : -1,
                    'state' => 'unknown'
                ];
            }
            $enrichedClients[] = $client;
        }

        // If admin, also fetch all agents list with their summary
        $allAgents = [];
        if ($isAdmin) {
            $agentRes = $connection->query("SELECT userid, name, username, wallet, agent_volume, agent_limit, agent_test_limit, is_agent FROM `users` WHERE `is_agent` = 1 ORDER BY `id` DESC");
            if ($agentRes) {
                while ($aRow = $agentRes->fetch_assoc()) {
                    // Count this agent's sold configs
                    $cntStmt = $connection->prepare("SELECT COUNT(*) as cnt FROM `orders_list` WHERE `userid` = ? AND `agent_bought` = 1");
                    $aUid = intval($aRow['userid']);
                    $cntStmt->bind_param("i", $aUid);
                    $cntStmt->execute();
                    $aRow['configs_sold'] = intval($cntStmt->get_result()->fetch_assoc()['cnt']);
                    $cntStmt->close();
                    $allAgents[] = $aRow;
                }
            }
        }

        echo json_encode([
            'status' => 'success',
            'agent' => [
                'volume' => floatval($userInfo['agent_volume'] ?? 0),
                'limit' => intval($userInfo['agent_limit'] ?? 0),
                'test_limit' => intval($userInfo['agent_test_limit'] ?? 0)
            ],
            'clients' => $enrichedClients,
            'agents_list' => $allAgents
        ]);
        break;

    case 'agent_purchase_volume':
        if (!$isAgent) {
            echo json_encode(['error' => 'دسترسی غیرمجاز']);
            exit;
        }
        
        $volumeAmount = intval($input['volume'] ?? 0); // in GB
        $pricePerGb = 1000; // configurable or fetched from settings
        $totalCost = $volumeAmount * $pricePerGb;

        if ($volumeAmount <= 0) {
            echo json_encode(['error' => 'مقدار حجم وارد شده نامعتبر است']);
            exit;
        }

        if (floatval($userInfo['wallet']) < $totalCost) {
            echo json_encode(['error' => 'اعتبار کیف پول کافی نیست.']);
            exit;
        }

        // Deduct cost and update volume quota
        $newWallet = floatval($userInfo['wallet']) - $totalCost;
        $newVolume = floatval($userInfo['agent_volume'] ?? 0) + $volumeAmount;

        $upStmt = $connection->prepare("UPDATE `users` SET `wallet` = ?, `agent_volume` = ? WHERE `userid` = ?");
        $upStmt->bind_param("ddi", $newWallet, $newVolume, $userId);
        $upStmt->execute();
        $upStmt->close();

        // Log payment transaction
        $hashId = uniqid('agent_vol_');
        $desc = "خرید عمده $volumeAmount گیگابایت ترافیک نماینده";
        $now = time();
        $state = 'approved';
        $type = 'agent_purchase';

        $payStmt = $connection->prepare("INSERT INTO `pays` (`hash_id`, `description`, `user_id`, `type`, `price`, `request_date`, `state`) VALUES (?, ?, ?, ?, ?, ?, ?)");
        $payStmt->bind_param("ssisiis", $hashId, $desc, $userId, $type, $totalCost, $now, $state);
        $payStmt->execute();
        $payStmt->close();

        echo json_encode([
            'status' => 'success',
            'wallet' => $newWallet,
            'volume' => $newVolume,
            'message' => 'خرید حجم با موفقیت انجام شد.'
        ]);
        break;

    case 'agent_create_custom_config':
        if (!$isAgent) {
            echo json_encode(['error' => 'دسترسی غیرمجاز']);
            exit;
        }

        $serverId = intval($input['server_id'] ?? 0);
        $remark = trim($input['remark'] ?? '');
        $volume = intval($input['volume'] ?? 0);
        $days = intval($input['days'] ?? 0);
        $limitip = intval($input['limitip'] ?? 0);

        if ($serverId <= 0) {
            echo json_encode(['error' => 'سرور نامعتبر است']);
            exit;
        }

        if (empty($remark)) {
            $remark = "agency-" . $userId . "-" . rand(1000, 9999);
        }

        if (!preg_match('/^[a-zA-Z0-9\-]+$/', $remark) || strlen($remark) < 2) {
            echo json_encode(['error' => 'نام کاربری فقط می‌تواند شامل حروف انگلیسی، اعداد و خط‌تیره باشد']);
            exit;
        }

        if ($volume <= 0) {
            echo json_encode(['error' => 'حجم کانفیگ باید بیشتر از صفر باشد']);
            exit;
        }

        if ($days <= 0) {
            echo json_encode(['error' => 'مدت اعتبار کانفیگ باید بیشتر از صفر باشد']);
            exit;
        }

        // Fetch agent info
        $agentVolume = floatval($userInfo['agent_volume'] ?? 0);
        $agentLimit  = intval($userInfo['agent_limit'] ?? 0);

        $volumeExceeded = ($agentVolume > 0) && ($agentVolume < $volume);
        $limitExceeded  = ($agentLimit > 0) && ($agentLimit < 1);
        
        if ($volumeExceeded || $limitExceeded) {
            echo json_encode(['error' => 'موجودی سهمیه حجم یا اکانت شما کافی نیست.']);
            exit;
        }

        // Fetch server config details
        $stmt = $connection->prepare("SELECT * FROM `server_config` WHERE `id` = ?");
        $stmt->bind_param("i", $serverId);
        $stmt->execute();
        $serverConfig = $stmt->get_result()->fetch_assoc();
        $stmt->close();

        if (!$serverConfig) {
            echo json_encode(['error' => 'سرور یافت نشد']);
            exit;
        }

        $serverType  = $serverConfig['type'];
        $panelUrl    = rtrim($serverConfig['panel_url'], '/');
        $apiToken    = trim($serverConfig['password']);
        $parsedUrl   = parse_url($panelUrl);
        $panelHost   = $parsedUrl['host'] ?? '';
        $panelScheme = $parsedUrl['scheme'] ?? 'https';

        $configLinks = [];
        $clientSubId = "";
        $clientUuid  = "";
        $finalEmail  = $remark . "@tg.com";
        $volumeBytes = $volume * 1073741824;
        $expiryTimeMs = $days > 0 ? (time() + ($days * 86400)) * 1000 : 0;

        if ($serverType == "marzban") {
            $response = addMarzbanUser($serverId, $remark, $volume, $days, 0);
            if (is_object($response) && isset($response->sub_link)) {
                $configLinks[] = $panelUrl . $response->sub_link;
                $clientSubId = $clientUuid = str_replace("/sub/", "", $response->sub_link);
            }
        } else {
            // Sanaei
            $allInboundIds = [];
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL, $panelUrl . '/panel/api/inbounds/list');
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch, CURLOPT_HTTPHEADER, ['Accept: application/json', 'Authorization: Bearer ' . $apiToken]);
            $listRes = curl_exec($ch);
            curl_close($ch);
            $listDec = json_decode($listRes, true);
            if (isset($listDec['success']) && $listDec['success'] && is_array($listDec['obj'])) {
                foreach ($listDec['obj'] as $inb) {
                    if (isset($inb['enable']) && $inb['enable'] == true) {
                        $allInboundIds[] = intval($inb['id']);
                    }
                }
            }
            if (empty($allInboundIds)) {
                $allInboundIds = [1];
            }

            $clientUuid = generateUID();
            $response = addInboundAccount($serverId, $clientUuid, $allInboundIds[0], $expiryTimeMs, $remark, $volume, $limitip, null, 0);
            if (is_object($response) && $response->success) {
                $clientSubId = basename($response->subLink);
                $subDec = callXuiApi($serverConfig, '/panel/api/clients/links/' . urlencode($remark));
                if ($subDec && isset($subDec->success) && $subDec->success && is_array($subDec->obj)) {
                    $configLinks = $subDec->obj;
                }
            }
        }

        if (empty($clientSubId) && !empty($clientUuid)) {
            $clientSubId = $clientUuid;
        }

        if (empty($configLinks) && $clientUuid != "") {
            $configLinks[] = "vless://{$clientUuid}@{$panelHost}:2096?type=tcp&security=none#{$remark}";
        }

        if (empty($configLinks)) {
            echo json_encode(['error' => 'ارتباط با سرور برقرار نشد یا نام کاربری از قبل وجود دارد.']);
            exit;
        }

        // Filter Links by Port
        $filteredLinks = [];
        if ($serverType != "marzban") {
            $inbound1Port = null;
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL, $panelUrl . '/panel/api/inbounds/get/1');
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch, CURLOPT_HTTPHEADER, ['Accept: application/json', 'Authorization: Bearer ' . $apiToken]);
            $inb1Res = curl_exec($ch);
            curl_close($ch);
            $inb1Dec = json_decode($inb1Res, true);
            if (isset($inb1Dec['success']) && $inb1Dec['success'] && isset($inb1Dec['obj']['port'])) {
                $inbound1Port = intval($inb1Dec['obj']['port']);
            }

            if ($inbound1Port !== null && !empty($configLinks)) {
                foreach ($configLinks as $link) {
                    if (strpos($link, 'vmess://') === 0) {
                        $base64Part = substr($link, 8);
                        $decoded = json_decode(base64_decode($base64Part), true);
                        if (isset($decoded['port']) && intval($decoded['port']) == $inbound1Port) {
                            $filteredLinks[] = $link;
                        }
                    } else {
                        if (strpos($link, ":" . $inbound1Port) !== false) {
                            $filteredLinks[] = $link;
                        }
                    }
                }
            }
        }

        if (empty($filteredLinks) && !empty($configLinks)) {
            $filteredLinks = [$configLinks[0]];
        }

        // Deduct Quota
        if ($agentVolume > 0 && $agentLimit > 0) {
            $stmt = $connection->prepare("UPDATE `users` SET `agent_volume` = GREATEST(0, `agent_volume` - ?), `agent_limit` = GREATEST(0, `agent_limit` - 1) WHERE `userid` = ?");
            $stmt->bind_param("di", $volume, $userId);
        } elseif ($agentVolume > 0) {
            $stmt = $connection->prepare("UPDATE `users` SET `agent_volume` = GREATEST(0, `agent_volume` - ?) WHERE `userid` = ?");
            $stmt->bind_param("di", $volume, $userId);
        } elseif ($agentLimit > 0) {
            $stmt = $connection->prepare("UPDATE `users` SET `agent_limit` = GREATEST(0, `agent_limit` - 1) WHERE `userid` = ?");
            $stmt->bind_param("i", $userId);
        }
        if (isset($stmt)) {
            $stmt->execute();
            $stmt->close();
        }

        $date        = time();
        $expire_date = ($days > 0) ? $date + (86400 * $days) : 0;
        $linkForDb   = json_encode($filteredLinks, JSON_UNESCAPED_UNICODE);
        $eachPrice   = 0;

        // Insert into orders_list
        $stmt = $connection->prepare("INSERT INTO `orders_list`
            (`userid`, `token`, `transid`, `fileid`, `server_id`, `inbound_id`, `remark`, `uuid`, `protocol`, `expire_date`, `link`, `amount`, `status`, `date`, `notif`, `rahgozar`, `agent_bought`)
            VALUES (?, ?, '', 0, ?, 0, ?, ?, 'vless/vmess/trojan', ?, ?, ?, 1, ?, 0, 0, 1);");
        $stmt->bind_param("isissisii", $userId, $clientSubId, $serverId, $remark, $clientSubId, $expire_date, $linkForDb, $eachPrice, $date);
        $stmt->execute();
        $stmt->close();

        // Update ucount in server_info
        $stmt = $connection->prepare("UPDATE `server_info` SET `ucount` = `ucount` - 1 WHERE `id` = ?");
        $stmt->bind_param("i", $serverId);
        $stmt->execute();
        $stmt->close();

        echo json_encode([
            'status' => 'success',
            'config' => [
                'remark' => $remark,
                'link' => $filteredLinks[0] ?? '',
                'subscription' => "{$panelScheme}://{$panelHost}:2096/sub/{$clientSubId}",
                'web_link' => rtrim($botUrl, '/') . "/search.php?id={$clientSubId}"
            ]
        ]);
        break;

    case 'agent_create_test_config':
        if (!$isAgent) {
            echo json_encode(['error' => 'دسترسی غیرمجاز']);
            exit;
        }

        $serverId = intval($input['server_id'] ?? 0);
        if ($serverId <= 0) {
            $srvRes = $connection->query("SELECT id FROM `server_info` WHERE `active` = 1 AND `state` = 1 LIMIT 1");
            if ($srvRes && $srvRes->num_rows > 0) {
                $serverId = intval($srvRes->fetch_assoc()['id']);
            }
        }
        if ($serverId <= 0) {
            echo json_encode(['error' => 'هیچ سرور فعال و در دسترسی یافت نشد.']);
            exit;
        }

        $agentTestLimit = intval($userInfo['agent_test_limit'] ?? 0);
        if ($agentTestLimit <= 0) {
            echo json_encode(['error' => 'سهمیه اکانت تست شما کافی نیست.']);
            exit;
        }

        // Fetch server config details
        $stmt = $connection->prepare("SELECT * FROM `server_config` WHERE `id` = ?");
        $stmt->bind_param("i", $serverId);
        $stmt->execute();
        $serverConfig = $stmt->get_result()->fetch_assoc();
        $stmt->close();

        if (!$serverConfig) {
            echo json_encode(['error' => 'سرور یافت نشد']);
            exit;
        }

        $remark = "agency(Gift)-" . $userId . "-" . rand(10000, 99999);
        $volume = 1; // 1 GB
        $days = 1;   // 1 day
        $limitip = 1;

        $serverType  = $serverConfig['type'];
        $panelUrl    = rtrim($serverConfig['panel_url'], '/');
        $parsedUrl   = parse_url($panelUrl);
        $panelHost   = $parsedUrl['host'] ?? '';
        $panelScheme = $parsedUrl['scheme'] ?? 'https';

        $configLinks = [];
        $clientSubId = "";
        $clientUuid  = "";

        if ($serverType == "marzban") {
            $response = addMarzbanUser($serverId, $remark, $volume, $days, 0);
            if (is_object($response) && isset($response->sub_link)) {
                $configLinks[] = $panelUrl . $response->sub_link;
                $clientSubId = $clientUuid = str_replace("/sub/", "", $response->sub_link);
            }
        } else {
            $clientUuid = generateUID();
            $expiryTimeMs = (time() + 86400) * 1000;
            $response = addInboundAccount($serverId, $clientUuid, 1, $expiryTimeMs, $remark, $volume, $limitip, null, 0);

            if (is_null($response) || !$response->success) {
                $errorDetails = isset($response->msg) ? $response->msg : "خطا در ارتباط با سرور";
                echo json_encode(['error' => 'خطا در صدور از سمت پنل سرور: ' . $errorDetails]);
                exit;
            }

            $clientSubId = basename($response->subLink);

            // Fetch links from xui
            $subDecodedObj = callXuiApi($serverConfig, '/panel/api/clients/links/' . urlencode($remark));
            if ($subDecodedObj && isset($subDecodedObj->success) && $subDecodedObj->success && is_array($subDecodedObj->obj)) {
                $configLinks = $subDecodedObj->obj;
            }
        }

        $filteredLinks = [];
        if (!empty($configLinks)) {
            $filteredLinks = [$configLinks[0]];
        } else {
            $filteredLinks = ["vless://{$clientUuid}@{$panelHost}:2096?type=tcp&security=none#{$remark}"];
        }

        // Deduct test limit
        $upStmt = $connection->prepare("UPDATE `users` SET `agent_test_limit` = GREATEST(0, `agent_test_limit` - 1) WHERE `userid` = ?");
        $upStmt->bind_param("i", $userId);
        $upStmt->execute();
        $upStmt->close();

        // Update ucount in server_info
        $stmt = $connection->prepare("UPDATE `server_info` SET `ucount` = `ucount` - 1 WHERE `id` = ?");
        $stmt->bind_param("i", $serverId);
        $stmt->execute();
        $stmt->close();

        $date        = time();
        $expire_date = $date + 86400;
        $linkForDb   = json_encode($filteredLinks, JSON_UNESCAPED_UNICODE);
        $eachPrice   = 0;

        // Insert into orders_list
        $stmt = $connection->prepare("INSERT INTO `orders_list`
            (`userid`, `token`, `transid`, `fileid`, `server_id`, `inbound_id`, `remark`, `uuid`, `protocol`, `expire_date`, `link`, `amount`, `status`, `date`, `notif`, `rahgozar`, `agent_bought`)
            VALUES (?, ?, '', 0, ?, 0, ?, ?, 'vless/vmess/trojan', ?, ?, ?, 1, ?, 0, 0, 1);");
        $stmt->bind_param("isissisii", $userId, $clientSubId, $serverId, $remark, $clientSubId, $expire_date, $linkForDb, $eachPrice, $date);
        $stmt->execute();
        $stmt->close();

        echo json_encode([
            'status' => 'success',
            'config' => [
                'remark' => $remark,
                'link' => $filteredLinks[0] ?? '',
                'subscription' => "{$panelScheme}://{$panelHost}:2096/sub/{$clientSubId}",
                'web_link' => rtrim($botUrl, '/') . "/search.php?id={$clientSubId}"
            ]
        ]);
        break;

    case 'agent_buy_quota':
        if (!$isAgent) {
            echo json_encode(['error' => 'دسترسی غیرمجاز']);
            exit;
        }

        $planId = intval($input['plan_id'] ?? 0);
        if ($planId <= 0) {
            echo json_encode(['error' => 'طرح نامعتبر است']);
            exit;
        }

        // Fetch plan details
        $stmt = $connection->prepare("SELECT * FROM `server_plans` WHERE `id` = ? AND `active` = 1 AND `type` = 'agent_quota'");
        $stmt->bind_param("i", $planId);
        $stmt->execute();
        $plan = $stmt->get_result()->fetch_assoc();
        $stmt->close();

        if (!$plan) {
            echo json_encode(['error' => 'طرح سهمیه یافت نشد یا غیرفعال است']);
            exit;
        }

        $totalPrice = intval($plan['price']);
        
        // Calculate reseller discount
        $discounts = json_decode($userInfo['discount_percent'] ?? '', true) ?? [];
        $serverId = intval($plan['server_id']);
        if (($botState['agencyPlanDiscount'] ?? "") == "on") {
            $discount = $discounts['plans'][$planId] ?? ($discounts['normal'] ?? 0);
        } else {
            $discount = $discounts['servers'][$serverId] ?? ($discounts['normal'] ?? 0);
        }
        $totalPrice -= floor($totalPrice * $discount / 100);

        if (floatval($userInfo['wallet']) < $totalPrice) {
            echo json_encode(['error' => 'اعتبار کیف پول شما کافی نیست.']);
            exit;
        }

        // Deduct wallet
        $stmt = $connection->prepare("UPDATE `users` SET `wallet` = `wallet` - ? WHERE `userid` = ?");
        $stmt->bind_param("ii", $totalPrice, $userId);
        $stmt->execute();
        $stmt->close();

        $vol_added = floatval($plan['volume']);
        $lim_added = intval($plan['acount']);
        $pDays = intval($plan['days']);
        $extend_seconds = $pDays * 86400;
        $current_agent_date = intval($userInfo['agent_date']);
        $new_agent_date = ($current_agent_date > time()) ? ($current_agent_date + $extend_seconds) : (time() + $extend_seconds);

        // Update reseller quota
        $stmt = $connection->prepare("UPDATE `users` SET `agent_volume` = `agent_volume` + ?, `agent_limit` = `agent_limit` + ?, `agent_date` = ? WHERE `userid` = ?");
        $stmt->bind_param("diii", $vol_added, $lim_added, $new_agent_date, $userId);
        $stmt->execute();
        $stmt->close();

        // Log payment in approved state
        $hashId = RandomString(12);
        $timeVal = time();
        $stmt = $connection->prepare("INSERT INTO `pays` (`user_id`, `price`, `volume`, `day`, `type`, `state`, `hash_id`, `plan_id`, `request_date`) VALUES (?, ?, ?, ?, 'BUY_AGENT_QUOTA', 'approved', ?, ?, ?)");
        $stmt->bind_param("iiiisii", $userId, $totalPrice, $vol_added, $lim_added, $hashId, $planId, $timeVal);
        $stmt->execute();
        $stmt->close();

        echo json_encode([
            'status' => 'success',
            'wallet' => floatval($userInfo['wallet']) - $totalPrice,
            'agent_volume' => floatval($userInfo['agent_volume']) + $vol_added,
            'agent_limit' => intval($userInfo['agent_limit']) + $lim_added,
            'message' => 'خرید سهمیه با موفقیت انجام شد'
        ]);
        break;

    case 'agent_modify_config':
        if (!$isAgent) {
            echo json_encode(['error' => 'دسترسی غیرمجاز']);
            exit;
        }

        $orderId = intval($input['order_id'] ?? 0);
        $actionType = trim($input['action_type'] ?? '');
        $value = floatval($input['value'] ?? 0);

        if ($orderId <= 0 || $value <= 0 || !in_array($actionType, ['add_volume', 'add_days'])) {
            echo json_encode(['error' => 'پارامترهای ارسالی نامعتبر است']);
            exit;
        }

        // Fetch order details & verify ownership
        $stmt = $connection->prepare("SELECT * FROM `orders_list` WHERE `id` = ? AND `userid` = ? AND `agent_bought` = 1");
        $stmt->bind_param("ii", $orderId, $userId);
        $stmt->execute();
        $order = $stmt->get_result()->fetch_assoc();
        $stmt->close();

        if (!$order) {
            echo json_encode(['error' => 'کانفیگ یافت نشد یا دسترسی غیرمجاز است']);
            exit;
        }

        $serverId = intval($order['server_id']);
        $remark   = $order['remark'];
        $uuid     = $order['uuid'];
        $token    = $order['token'];

        // Fetch server config details
        $stmt = $connection->prepare("SELECT * FROM `server_config` WHERE `id` = ?");
        $stmt->bind_param("i", $serverId);
        $stmt->execute();
        $serverConfig = $stmt->get_result()->fetch_assoc();
        $stmt->close();

        if (!$serverConfig) {
            echo json_encode(['error' => 'سرور یافت نشد']);
            exit;
        }

        $isMarzban = ($serverConfig['type'] == 'marzban');

        if ($actionType === 'add_volume') {
            // Check volume quota
            $agentVolume = floatval($userInfo['agent_volume'] ?? 0);
            if ($agentVolume > 0 && $agentVolume < $value) {
                echo json_encode(['error' => 'سهمیه حجم شما کافی نیست']);
                exit;
            }

            // Update Panel traffic
            if ($isMarzban) {
                $response = editMarzbanConfig($serverId, ['remark' => $remark, 'plus_volume' => $value]);
                $success = ($response !== null);
            } else {
                $response = editClientTraffic($serverId, intval($order['inbound_id']), $uuid, $value, 0);
                $success = ($response && isset($response->success) && $response->success);
            }

            if (!$success) {
                echo json_encode(['error' => 'خطا در افزایش حجم در پنل سرور']);
                exit;
            }

            // Deduct Quota (if agentVolume > 0)
            if ($agentVolume > 0) {
                $stmt = $connection->prepare("UPDATE `users` SET `agent_volume` = GREATEST(0, `agent_volume` - ?) WHERE `userid` = ?");
                $stmt->bind_param("di", $value, $userId);
                $stmt->execute();
                $stmt->close();
            }

            // No database fileid update required since database doesn't store current volume limit, and fileid represents plan ID.

            echo json_encode([
                'status' => 'success',
                'message' => 'حجم کانفیگ با موفقیت افزایش یافت',
                'new_agent_volume' => ($agentVolume > 0) ? max(0, $agentVolume - $value) : 0
            ]);
            break;

        } else if ($actionType === 'add_days') {
            // Update Panel expiration
            if ($isMarzban) {
                $response = editMarzbanConfig($serverId, ['remark' => $remark, 'plus_day' => $value]);
                $success = ($response !== null);
            } else {
                $response = editClientTraffic($serverId, intval($order['inbound_id']), $uuid, 0, $value);
                $success = ($response && isset($response->success) && $response->success);
            }

            if (!$success) {
                echo json_encode(['error' => 'خطا در افزایش زمان در پنل سرور']);
                exit;
            }

            // Update database expiration date in `orders_list`
            $currentExpire = intval($order['expire_date']);
            $baseTime = ($currentExpire > time()) ? $currentExpire : time();
            $newExpire = $baseTime + ($value * 86400);

            $stmt = $connection->prepare("UPDATE `orders_list` SET `expire_date` = ? WHERE `id` = ?");
            $stmt->bind_param("ii", $newExpire, $orderId);
            $stmt->execute();
            $stmt->close();

            echo json_encode([
                'status' => 'success',
                'message' => 'مدت زمان کانفیگ با موفقیت افزایش یافت',
                'new_expire_date' => $newExpire
            ]);
            break;
        }
        break;

    // ----------------------------------------------------
    // ADMINISTRATIVE ACTIONS
    // ----------------------------------------------------
    case 'admin_dashboard':
        if (!$isAdmin) {
            echo json_encode(['error' => 'دسترسی غیرمجاز به بخش مدیریت']);
            exit;
        }

        // Fetch basic counts
        $totalUsers = $connection->query("SELECT COUNT(*) as cnt FROM `users`")->fetch_assoc()['cnt'] ?? 0;
        $totalServers = $connection->query("SELECT COUNT(*) as cnt FROM `servers`")->fetch_assoc()['cnt'] ?? 0;
        $totalConfigs = $connection->query("SELECT COUNT(*) as cnt FROM `orders_list`")->fetch_assoc()['cnt'] ?? 0;
        $pendingPays = $connection->query("SELECT COUNT(*) as cnt FROM `pays` WHERE `state` = 'pending'")->fetch_assoc()['cnt'] ?? 0;

        // Pending manual payments queue
        $receiptsRes = $connection->query("SELECT p.*, u.name as user_name FROM `pays` p LEFT JOIN `users` u ON p.user_id = u.userid WHERE p.state = 'pending' ORDER BY p.id DESC");
        $receipts = $receiptsRes ? $receiptsRes->fetch_all(MYSQLI_ASSOC) : [];

        // Active support tickets queue
        $ticketsRes = $connection->query("SELECT c.*, u.name as user_name FROM `chats` c LEFT JOIN `users` u ON c.user_id = u.userid WHERE c.state != 2 ORDER BY c.id DESC");
        $allTickets = $ticketsRes ? $ticketsRes->fetch_all(MYSQLI_ASSOC) : [];
        $totalOpenTickets = $connection->query("SELECT COUNT(*) as cnt FROM `chats` WHERE `state` != 2")->fetch_assoc()['cnt'] ?? 0;

        echo json_encode([
            'status' => 'success',
            'stats' => [
                'users' => $totalUsers,
                'servers' => $totalServers,
                'configs' => $totalConfigs,
                'pending_payments' => $pendingPays,
                'active_tickets' => $totalOpenTickets
            ],
            'pending_receipts' => $receipts,
            'active_tickets' => $allTickets
        ]);
        break;

    case 'admin_users':
        if (!$isAdmin) {
            echo json_encode(['error' => 'دسترسی غیرمجاز']);
            exit;
        }
        
        $search = trim($input['query'] ?? '');
        if (!empty($search)) {
            $stmt = $connection->prepare("SELECT * FROM `users` WHERE `name` LIKE ? OR `username` LIKE ? OR `userid` LIKE ? ORDER BY `id` DESC LIMIT 30");
            $like = "%$search%";
            $stmt->bind_param("sss", $like, $like, $like);
        } else {
            $stmt = $connection->prepare("SELECT * FROM `users` ORDER BY `id` DESC LIMIT 30");
        }
        $stmt->execute();
        $usersList = $stmt->get_result()->fetch_all(MYSQLI_ASSOC);
        $stmt->close();

        echo json_encode(['status' => 'success', 'users' => $usersList]);
        break;

    case 'admin_edit_user':
        if (!$isAdmin) {
            echo json_encode(['error' => 'دسترسی غیرمجاز']);
            exit;
        }

        $targetUserId = intval($input['target_user_id']);
        $newBalance = floatval($input['wallet'] ?? 0);
        $newIsAgent = intval($input['is_agent'] ?? 0);
        $newIsAdmin = intval($input['is_admin'] ?? 0);
        $newVolume = floatval($input['agent_volume'] ?? 0);
        $newLimit = intval($input['agent_limit'] ?? 0);
        
        $stmt = $connection->prepare("UPDATE `users` SET `wallet` = ?, `is_agent` = ?, `isAdmin` = ?, `agent_volume` = ?, `agent_limit` = ? WHERE `userid` = ?");
        $stmt->bind_param("diiidi", $newBalance, $newIsAgent, $newIsAdmin, $newVolume, $newLimit, $targetUserId);
        $stmt->execute();
        $stmt->close();

        echo json_encode(['status' => 'success', 'message' => 'پروفایل کاربر با موفقیت ویرایش شد.']);
        break;

    case 'admin_delete_agent':
        if (!$isAdmin) {
            echo json_encode(['error' => 'دسترسی غیرمجاز']);
            exit;
        }

        $targetUserId = intval($input['target_user_id']);
        if ($targetUserId <= 0) {
            echo json_encode(['error' => 'شناسه نماینده نامعتبر است.']);
            exit;
        }

        // Revoke reseller status by setting is_agent = 0
        $stmt = $connection->prepare("UPDATE `users` SET `is_agent` = 0 WHERE `userid` = ?");
        $stmt->bind_param("i", $targetUserId);
        $stmt->execute();
        $stmt->close();

        echo json_encode(['status' => 'success', 'message' => 'نماینده با موفقیت حذف شد (به کاربر عادی تبدیل شد).']);
        break;

    case 'admin_msg_agent':
        if (!$isAdmin) {
            echo json_encode(['error' => 'دسترسی غیرمجاز']);
            exit;
        }

        $targetUserId = intval($input['target_user_id']);
        $messageText = trim($input['message'] ?? '');

        if ($targetUserId <= 0 || empty($messageText)) {
            echo json_encode(['error' => 'اطلاعات ارسالی ناقص است.']);
            exit;
        }

        // Send direct message using bot's sendMessage function
        $sendRes = sendMessage($messageText, null, "HTML", $targetUserId);
        if ($sendRes && isset($sendRes->ok) && $sendRes->ok) {
            echo json_encode(['status' => 'success', 'message' => 'پیام خصوصی با موفقیت به نماینده ارسال شد.']);
        } else {
            echo json_encode(['error' => 'ارسال پیام ناموفق بود. مطمئن شوید کاربر ربات را بلاک نکرده است.']);
        }
        break;

    case 'admin_verify_payment':
        if (!$isAdmin) {
            echo json_encode(['error' => 'دسترسی غیرمجاز']);
            exit;
        }

        $payId = intval($input['pay_id']);
        $decision = trim($input['decision']); // approve, decline

        $stmt = $connection->prepare("SELECT * FROM `pays` WHERE `id` = ?");
        $stmt->bind_param("i", $payId);
        $stmt->execute();
        $payment = $stmt->get_result()->fetch_assoc();
        $stmt->close();

        if (!$payment) {
            echo json_encode(['error' => 'تراکنش یافت نشد']);
            exit;
        }

        if ($payment['state'] !== 'pending') {
            echo json_encode(['error' => 'تراکنش قبلا پردازش شده است']);
            exit;
        }

        $newState = ($decision === 'approve') ? 'approved' : 'rejected';
        
        $upStmt = $connection->prepare("UPDATE `pays` SET `state` = ? WHERE `id` = ?");
        $upStmt->bind_param("si", $newState, $payId);
        $upStmt->execute();
        $upStmt->close();

        if ($decision === 'approve') {
            $creditor = intval($payment['user_id']);
            $creditAmount = floatval($payment['price']);
            
            // If request_agency payment type
            if ($payment['type'] === 'request_agency') {
                $userUp = $connection->prepare("UPDATE `users` SET `is_agent` = 1, `agent_volume` = 100, `agent_limit` = 10 WHERE `userid` = ?");
                $userUp->bind_param("i", $creditor);
                $userUp->execute();
                $userUp->close();
            } else {
                // Charge normal user wallet
                $userUp = $connection->prepare("UPDATE `users` SET `wallet` = `wallet` + ? WHERE `userid` = ?");
                $userUp->bind_param("di", $creditAmount, $creditor);
                $userUp->execute();
                $userUp->close();
            }
        }

        echo json_encode(['status' => 'success', 'message' => 'تصمیم با موفقیت ثبت و بر کیف پول کاربر اعمال شد.']);
        break;

    default:
        http_response_code(400);
        echo json_encode(['error' => 'اکشن نامعتبر است']);
        break;
}

// ----------------------------------------------------
// Real-Time Bandwidth Statistics Fetcher
// ----------------------------------------------------
function fetchSubscriptionRealTimeStats($connection, $serverId, $client_email, $uuid = '', $token = '') {
    if (empty($client_email)) return null;

    $stmt = $connection->prepare("SELECT * FROM `server_config` WHERE `id` = ?");
    $stmt->bind_param("i", $serverId);
    $stmt->execute();
    $serverRow = $stmt->get_result()->fetch_assoc();
    $stmt->close();

    if (!$serverRow) return null;

    $serverType = $serverRow['type'];
    $panelUrl = rtrim($serverRow['panel_url'], '/');
    if (strpos($panelUrl, '://') === false) {
        $panelUrl = 'https://' . $panelUrl;
    }
    $apiToken = trim($serverRow['password']);

    if ($serverType == "marzban") {
        require_once __DIR__ . '/config.php';
        $usersList = getMarzbanJson($serverId)->users ?? [];
        foreach ($usersList as $config) {
            if ($config->username == $client_email || strstr(json_encode($config->links ?? [], JSON_UNESCAPED_UNICODE), $client_email)) {
                $total = $config->data_limit ?? 0;
                $used = $config->used_traffic ?? 0;
                $remaining = $total > 0 ? max(0, $total - $used) : 0;
                $expire = $config->expire ?? 0;
                $expiryDays = $expire > 0 ? max(0, floor(($expire - time()) / 86400)) : -1;
                $state = $config->status ?? 'active';
                return [
                    'total' => $total,
                    'used' => $used,
                    'remaining' => $remaining,
                    'expiry_time' => $expire,
                    'expiry_days' => $expiryDays,
                    'state' => $state
                ];
            }
        }
    } else {
        // Sanaei/X-UI
        include_once __DIR__ . '/settings/config_xui_api.php';
        
        $found = false;
        $up = 0; $down = 0; $total = 0; $expTime = 0; $state = 'active';
        $onlineCount = 0;
        $limitIp = 0;
        
        // 1. Try `/panel/api/clients/list` first
        $clientsListRes = callXuiApi($serverRow, '/panel/api/clients/list');
        if ($clientsListRes && isset($clientsListRes->success) && $clientsListRes->success && is_array($clientsListRes->obj)) {
            foreach ($clientsListRes->obj as $c) {
                $clientId = $c->uuid ?? ($c->id ?? ($c->password ?? ''));
                $clientEmail = $c->email ?? '';
                $clientSubId = $c->subId ?? '';
                
                if ((!empty($uuid) && ($clientId === $uuid || $clientEmail === $uuid || $clientSubId === $uuid)) ||
                    (!empty($token) && ($clientId === $token || $clientEmail === $token || $clientSubId === $token)) ||
                    $clientEmail === $client_email ||
                    (!empty($clientEmail) && !empty($client_email) && (stripos($clientEmail, $client_email) !== false || stripos($client_email, $clientEmail) !== false))) {
                    
                    $found = true;
                    $traffic = $c->traffic ?? null;
                    
                    $up = $traffic ? ($traffic->up ?? 0) : ($c->up ?? 0);
                    $down = $traffic ? ($traffic->down ?? 0) : ($c->down ?? 0);
                    $total = $c->totalGB ?? ($traffic->total ?? 0);
                    $expTime = $c->expiryTime ?? ($traffic->expiryTime ?? 0);
                    $state = ($c->enable ?? ($traffic->enable ?? true)) ? 'active' : 'disabled';
                    $onlineCount = is_object($c) ? ($c->onlineCount ?? 0) : ($c['onlineCount'] ?? 0);
                    $limitIp = is_object($c) ? ($c->limitIp ?? 0) : ($c['limitIp'] ?? 0);
                    break;
                }
            }
        }
        
        // 2. Fallback to `/panel/api/inbounds/list` if not found in client list
        if (!$found) {
            $inboundsRes = getJson($serverId);
            if ($inboundsRes && isset($inboundsRes->success) && $inboundsRes->success && isset($inboundsRes->obj)) {
                $inbounds = $inboundsRes->obj;
                foreach ($inbounds as $inbound) {
                    $settings = json_decode($inbound->settings ?? '{}', true);
                    $clients = $settings['clients'] ?? [];
                    $clientStats = $inbound->clientStats ?? [];
                    
                    foreach ($clients as $client) {
                        $clientId = $client['id'] ?? ($client['password'] ?? '');
                        $clientEmail = $client['email'] ?? '';
                        
                        if ((!empty($uuid) && ($clientId === $uuid || $clientEmail === $uuid)) ||
                            (!empty($token) && ($clientId === $token || $clientEmail === $token)) ||
                            $clientEmail === $client_email || 
                            (!empty($clientEmail) && !empty($client_email) && (stripos($clientEmail, $client_email) !== false || stripos($client_email, $clientEmail) !== false))) {
                            
                            $found = true;
                            $up = 0; 
                            $down = 0; 
                            $total = isset($client['totalGB']) ? $client['totalGB'] : 0;
                            $expTime = isset($client['expiryTime']) ? $client['expiryTime'] : 0;
                            $limitIp = isset($client['limitIp']) ? $client['limitIp'] : 0;
                            $onlineCount = isset($client['onlineCount']) ? $client['onlineCount'] : 0;
                            
                            foreach ($clientStats as $stat) {
                                if (is_object($stat) && $stat->email == $clientEmail) {
                                    $up = $stat->up ?? 0;
                                    $down = $stat->down ?? 0;
                                    if (isset($stat->total) && $stat->total > 0) $total = $stat->total;
                                    if (isset($stat->expiryTime) && $stat->expiryTime > 0) $expTime = $stat->expiryTime;
                                    break;
                                } elseif (is_array($stat) && $stat['email'] == $clientEmail) {
                                    $up = $stat['up'] ?? 0;
                                    $down = $stat['down'] ?? 0;
                                    if (isset($stat['total']) && $stat['total'] > 0) $total = $stat['total'];
                                    if (isset($stat['expiryTime']) && $stat['expiryTime'] > 0) $expTime = $stat['expiryTime'];
                                    break;
                                }
                            }
                            
                            $state = (isset($client['enable']) && $client['enable'] == true) ? 'active' : 'disabled';
                            break;
                        }
                    }
                    if ($found) break;
                }
            }
        }
        
        $totalBytes = ($total < 1000000) ? ($total * 1073741824) : $total;
        $used = $up + $down;
        $remaining = $totalBytes > 0 ? max(0, $totalBytes - $used) : 0;
        $expire = $expTime > 0 ? intval(substr($expTime, 0, -3)) : 0;
        
        if ($expire > 0 && strlen((string)$expire) > 10) {
            $expire = intval(substr((string)$expire, 0, 10));
        }
        
        $expiryDays = $expire > 0 ? max(0, floor(($expire - time()) / 86400)) : -1;
        
        if ($totalBytes > 0 && $used >= $totalBytes) $state = "limited";
        elseif ($expire > 0 && $expire < time()) $state = "expired";
        
        return [
            'total' => $totalBytes,
            'used' => $used,
            'remaining' => $remaining,
            'expiry_time' => $expire,
            'expiry_days' => $expiryDays,
            'state' => $state,
            'online_count' => intval($onlineCount),
            'limit_ip' => intval($limitIp)
        ];
    }
    return null;
}
