<?php
// modules/pasarguard/pasarguard_api.php

// بافرینگ برای جلوگیری از چاپ هرگونه خطای مزاحم و حفظ خلوص فرمت JSON
ob_start();

require_once __DIR__ . '/../../includes/auth.php';
if (session_status() === PHP_SESSION_NONE) { session_start(); }

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

// تابع هوشمند برای ارسال دیتای خالص به جاوااسکریپت بدون هیچ ارور اضافی
function sendJson($data) {
    if (ob_get_length()) ob_clean(); // پاکسازی کاراکترهای مخفی و اسپیس‌ها
    header('Content-Type: application/json; charset=utf-8');
    echo json_encode($data);
    exit;
}

function executePsgApiCall($serverUrl, $endpoint, $method = 'GET', $data = null, $token = null) {
    // 💡 پاکسازی فواصل نامرئی از انتهای آدرس
    $url = rtrim(trim($serverUrl), '/') . $endpoint;
    $headers = [
        "User-Agent: VPNet-Panel",
        "Accept: application/json",
        "x-client-timezone: Asia/Tehran",
        "x-client-timezone-offset-minutes: 210"
    ];

    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_TIMEOUT, 60);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); 
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); 

    if ($method === 'POST') {
        curl_setopt($ch, CURLOPT_POST, true);
        if ($token) {
            $headers[] = "Authorization: Bearer " . trim($token);
            $headers[] = "Content-Type: application/json";
            if ($data) curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
        } else {
            $headers[] = "Content-Type: application/x-www-form-urlencoded;charset=UTF-8";
            curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
        }
    } elseif ($method === 'PUT' || $method === 'DELETE') {
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
        if ($token) {
            $headers[] = "Authorization: Bearer " . trim($token);
            if ($data) {
                $headers[] = "Content-Type: application/json";
                curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
            }
        }
    } elseif ($method === 'GET' && $token) {
        $headers[] = "Authorization: Bearer " . trim($token);
    }

    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $curlError = curl_error($ch);
    curl_close($ch);

    $decoded = json_decode($response, true);

    // 💡 شناسایی دقیق خطای منقضی شدن یا نامعتبر بودن توکن
    if ($httpCode === 401) {
        return [
            'code' => 401, 
            'error' => 'unauthorized', 
            'data' => $decoded, 
            'raw' => $response
        ];
    }

    return [
        'code' => $httpCode, 
        'data' => $decoded, 
        'raw' => $response, 
        'curl_error' => $curlError
    ];
}

function getPsgApiToken($serverId = null) {
    global $pdo;

    if ($serverId) {
        $stmt = $pdo->prepare("SELECT * FROM servers WHERE id = ?");
        $stmt->execute([$serverId]);
    } else {
        $stmt = $pdo->prepare("SELECT * FROM servers ORDER BY id ASC LIMIT 1");
        $stmt->execute();
    }
    
    $server = $stmt->fetch(PDO::FETCH_ASSOC);
    if (!$server) return ['success' => false, 'error' => 'هیچ سروری در دیتابیس تعریف نشده است.'];

    $sid = $server['id'];
    $serverUrl = rtrim(trim($server['url']), '/');

    if (isset($_SESSION['psg_token_'.$sid]) && $_SESSION['psg_token_expire_'.$sid] > time()) {
        return ['success' => true, 'token' => $_SESSION['psg_token_'.$sid], 'server_url' => $serverUrl, 'server_id' => $sid];
    }
    
    // 💡 اضافه کردن grant_type و حذف اسپیس‌های نامرئی برای جلوگیری از رد شدن در لینوکس
    $res = executePsgApiCall($serverUrl, "/api/admin/token", "POST", [
        "grant_type" => "password", 
        "username" => trim($server['username']), 
        "password" => trim($server['password'])
    ]);
    
    if ($res['code'] == 200 && isset($res['data']['access_token'])) {
        $_SESSION['psg_token_'.$sid] = $res['data']['access_token'];
        $_SESSION['psg_token_expire_'.$sid] = time() + 3000;
        return ['success' => true, 'token' => $res['data']['access_token'], 'server_url' => $serverUrl, 'server_id' => $sid];
    }
    
    // 💡 استخراج دلیل دقیق ارور 401 از خود پنل مارزبان
    $errorDetails = "کد HTTP: " . $res['code'];
    if (!empty($res['curl_error'])) {
        $errorDetails .= " | خطای شبکه: " . $res['curl_error'];
    } elseif ($res['code'] == 401 || $res['code'] == 422) {
        $marzbanMsg = isset($res['data']['detail']) ? (is_array($res['data']['detail']) ? json_encode($res['data']['detail']) : $res['data']['detail']) : 'دلیل نامشخص';
        $errorDetails .= " | پیام مارزبان: " . $marzbanMsg . " (لطفاً یوزرنیم و پسورد دیتابیس یا آی‌پی مجاز سرور را چک کنید)";
    } else {
        $errorDetails .= " | پاسخ نامشخص سرور.";
    }
    
    return ['success' => false, 'error' => $errorDetails];
}

if (isset($_GET['ajax_call']) || isset($_POST['ajax_call'])) {
    if (session_status() === PHP_SESSION_NONE) { session_start(); }
    
    $action = $_GET['ajax_call'] ?? $_POST['ajax_call'];
    
    // =========================================================================
    // 🔥 سیستم کنترل دسترسی هوشمند (ACL) برای نمایندگان
    // =========================================================================
    if (!isAdmin()) {
        $allowedForAgents = [
            'get_sub_links', 'system_stats', 'nodes', 'groups', 
            'users_list', 'get_user', 'edit_user', 'reset_user', 
            'delete_user', 'bulk_action', 'bulk_smart_edit'
        ];
        
        if (!in_array($action, $allowedForAgents)) {
            sendJson(['error' => 'دسترسی غیرمجاز به این بخش از API']);
        }
        
        // بررسی مالکیت اکانت قبل از اعمال هرگونه تغییر توسط نماینده
        $modifyActions = ['edit_user', 'reset_user', 'delete_user', 'bulk_action', 'bulk_smart_edit'];
        if (in_array($action, $modifyActions)) {
            global $pdo;
            $userId = $_SESSION['user_id'] ?? 0;
            $targetUsers = [];
            
            if ($action === 'bulk_action') {
                $targetUsers = $_POST['usernames'] ?? [];
            } else {
                $u = trim($_POST['username'] ?? $_GET['username'] ?? '');
                if ($u) $targetUsers[] = $u;
            }
            
            if (!empty($targetUsers)) {
                $placeholders = implode(',', array_fill(0, count($targetUsers), '?'));
                $stmt = $pdo->prepare("SELECT account_username FROM inventory WHERE account_username IN ($placeholders) AND operator_id = ?");
                $params = $targetUsers;
                $params[] = $userId;
                $stmt->execute($params);
                $ownedUsers = $stmt->fetchAll(PDO::FETCH_COLUMN);
                
                foreach ($targetUsers as $u) {
                    if (trim($u) !== '' && !in_array(trim($u), $ownedUsers)) {
                        sendJson(['error' => 'دسترسی غیرمجاز: اشتراک ' . htmlspecialchars($u) . ' متعلق به شما نیست!']);
                    }
                }
            }
        }
    }

    $reqServerId = $_GET['server_id'] ?? $_POST['server_id'] ?? null;

    // -- دریافت کانفیگ از لینک ساب --
    if ($action === 'get_sub_links') {
        $subUrl = trim($_GET['sub_url'] ?? '');
        if (!empty($subUrl)) {
            $ch = curl_init($subUrl);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_TIMEOUT, 15);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
            curl_setopt($ch, CURLOPT_HTTPHEADER, ["User-Agent: VPNet-Panel"]);
            $res = curl_exec($ch);
            
            if (curl_errno($ch)) {
                curl_close($ch);
                sendJson([]);
            }
            curl_close($ch);
            
            if ($res) {
                // 💡 دور زدن فرمت‌های خراب Base64
                $decoded = base64_decode(trim($res), true);
                if ($decoded === false || !preg_match('/^[a-zA-Z0-9\/\r\n+]*={0,2}$/', trim($res))) {
                    $decoded = $res;
                }
                $content = $decoded ? $decoded : $res;
                $links = array_filter(array_map('trim', explode("\n", str_replace("\r", "", $content))));
                sendJson(array_values($links));
            }
        }
        sendJson([]);
    }

    $tokenRes = getPsgApiToken($reqServerId);
    if (!$tokenRes['success']) { sendJson(['error' => $tokenRes['error']]); }
    
    $token = $tokenRes['token'];
    $serverUrl = $tokenRes['server_url'];

    // =========================================================================
    // 🚀 آزادسازی سشن برای ریکوئست‌های موازی جاوااسکریپت
    // =========================================================================
    session_write_close();

    if ($action === 'system_stats') {
        $res = executePsgApiCall($serverUrl, "/api/system", "GET", null, $token);
        sendJson($res['data']);
    }

    if ($action === 'nodes') {
        $res = executePsgApiCall($serverUrl, "/api/nodes", "GET", null, $token);
        sendJson($res['data']);
    }

    if ($action === 'groups') {
        $res = executePsgApiCall($serverUrl, "/api/group", "GET", null, $token); 
        if ($res['code'] == 404 || $res['code'] == 405) {
            $res = executePsgApiCall($serverUrl, "/api/groups", "GET", null, $token);
        }
        sendJson($res['data']);
    }

    if ($action === 'users_list') {
        $query = isset($_GET['search']) ? "?username=" . urlencode($_GET['search']) : "?limit=10000";
        $res = executePsgApiCall($serverUrl, "/api/users" . $query, "GET", null, $token);
        sendJson($res['data']);
    }

    if ($action === 'delete_user' && $_SERVER['REQUEST_METHOD'] === 'POST') {
        $username = trim($_POST['username'] ?? '');
        $res = executePsgApiCall($serverUrl, "/api/user/" . urlencode($username), "DELETE", null, $token);
        sendJson($res);
    }

    if ($action === 'reset_user' && $_SERVER['REQUEST_METHOD'] === 'POST') {
        $username = trim($_POST['username'] ?? '');
        $res = executePsgApiCall($serverUrl, "/api/user/" . urlencode($username) . "/reset", "POST", [], $token);
        sendJson($res);
    }

    if ($action === 'get_user') {
        $username = trim($_GET['username'] ?? '');
        $res = executePsgApiCall($serverUrl, "/api/user/" . urlencode($username), "GET", null, $token);
        sendJson($res);
    }

    if ($action === 'create_user' && $_SERVER['REQUEST_METHOD'] === 'POST') {
        $userData = [
            'username' => trim($_POST['username'] ?? ''),
            'status' => trim($_POST['status'] ?? 'active'),
            'note' => trim($_POST['note'] ?? ''),
            'data_limit_reset_strategy' => trim($_POST['reset_strategy'] ?? 'no_reset')
        ];
        
        $limitVal = isset($_POST['data_limit_val']) ? (float)$_POST['data_limit_val'] : (float)($_POST['data_limit_gb'] ?? 0);
        $limitUnit = $_POST['data_limit_unit'] ?? 'GB';
        $userData['data_limit'] = ($limitUnit === 'MB') ? (int)($limitVal * pow(1024, 2)) : (int)($limitVal * pow(1024, 3));
        
        if (!empty($_POST['expire_date'])) {
            date_default_timezone_set('Asia/Tehran');
            $userData['expire'] = date('Y-m-d\TH:i:sP', strtotime(trim($_POST['expire_date'])));
        } else {
            $userData['expire'] = null;
        }

        $proxies = [];
        if (isset($_POST['proxies']) && is_array($_POST['proxies'])) {
            foreach ($_POST['proxies'] as $proto) {
                $proxies[$proto] = ($proto === 'shadowsocks') ? ["method" => "chacha20-ietf-poly1305"] : new stdClass();
            }
        }
        if (empty($proxies)) $proxies['vless'] = new stdClass();
        $userData['proxies'] = $proxies;

        if (isset($_POST['group_ids']) && is_array($_POST['group_ids'])) {
            $userData['group_ids'] = array_map('intval', $_POST['group_ids']);
        }

        $res = executePsgApiCall($serverUrl, "/api/user", "POST", $userData, $token);
        sendJson($res);
    }

    if ($action === 'edit_user' && $_SERVER['REQUEST_METHOD'] === 'POST') {
        $username = trim($_POST['username'] ?? '');
        $current = executePsgApiCall($serverUrl, "/api/user/" . urlencode($username), "GET", null, $token);
        if ($current['code'] === 200 && isset($current['data']['username'])) {
            $userData = $current['data'];
            
            if (isset($_POST['status'])) $userData['status'] = trim($_POST['status']);
            if (isset($_POST['note'])) $userData['note'] = trim($_POST['note']);
            if (isset($_POST['reset_strategy'])) $userData['data_limit_reset_strategy'] = trim($_POST['reset_strategy']);
            
            if (isset($_POST['data_limit_val']) || isset($_POST['data_limit_gb'])) {
                $limitVal = isset($_POST['data_limit_val']) ? (float)$_POST['data_limit_val'] : (float)$_POST['data_limit_gb'];
                $limitUnit = $_POST['data_limit_unit'] ?? 'GB';
                $userData['data_limit'] = ($limitUnit === 'MB') ? (int)($limitVal * pow(1024, 2)) : (int)($limitVal * pow(1024, 3));
            }
            
            if (isset($_POST['expire_date'])) {
                $expire = trim($_POST['expire_date']);
                if (empty($expire)) {
                    $userData['expire'] = null;
                } else {
                    date_default_timezone_set('Asia/Tehran');
                    $userData['expire'] = date('Y-m-d\TH:i:sP', strtotime($expire));
                }
            }
            
            if (isset($_POST['proxies']) && is_array($_POST['proxies'])) {
                $newProxies = [];
                foreach ($_POST['proxies'] as $proto) {
                    $newProxies[$proto] = isset($userData['proxies'][$proto]) ? $userData['proxies'][$proto] : (($proto === 'shadowsocks') ? ["method" => "chacha20-ietf-poly1305"] : new stdClass());
                }
                $userData['proxies'] = empty($newProxies) ? new stdClass() : $newProxies;
            }

            if (isset($_POST['group_ids']) && is_array($_POST['group_ids'])) {
                $userData['group_ids'] = array_map('intval', $_POST['group_ids']);
            } else {
                $userData['group_ids'] = [];
            }

            $res = executePsgApiCall($serverUrl, "/api/user/" . urlencode($username), "PUT", $userData, $token);
            sendJson($res);
        } else {
            sendJson(['code' => 404, 'error' => 'کاربر یافت نشد.']);
        }
    }

    if ($action === 'bulk_action' && $_SERVER['REQUEST_METHOD'] === 'POST') {
        $usernames = $_POST['usernames'] ?? [];
        $bulkType = $_POST['bulk_type'] ?? ''; 
        $success = 0; $failed = 0;

        foreach ($usernames as $username) {
            $username = trim($username);
            if ($bulkType === 'delete') {
                $res = executePsgApiCall($serverUrl, "/api/user/" . urlencode($username), "DELETE", null, $token);
                if ($res['code'] == 200 || $res['code'] == 204) $success++; else $failed++;
            } elseif ($bulkType === 'reset') {
                $res = executePsgApiCall($serverUrl, "/api/user/" . urlencode($username) . "/reset", "POST", [], $token);
                if ($res['code'] == 200 || $res['code'] == 204) $success++; else $failed++;
            } elseif (in_array($bulkType, ['active', 'disabled', 'on_hold'])) {
                $current = executePsgApiCall($serverUrl, "/api/user/" . urlencode($username), "GET", null, $token);
                if ($current['code'] === 200 && isset($current['data']['username'])) {
                    $userData = $current['data'];
                    $userData['status'] = $bulkType;
                    $res = executePsgApiCall($serverUrl, "/api/user/" . urlencode($username), "PUT", $userData, $token);
                    if ($res['code'] == 200 || $res['code'] == 204) $success++; else $failed++;
                } else { $failed++; }
            }
        }
        sendJson(['status' => 'success', 'success_count' => $success, 'fail_count' => $failed]);
    }

    // =========================================================================
    // 🔥 بخش جدید افزوده شده: اکشن‌های اختصاصی ویرایش هوشمند دسته‌جمعی
    // =========================================================================

    // ۱. استخراج لیست طرح‌های ثبت شده در انبار (دیتابیس)
    if ($action === 'get_inventory_plans') {
        global $pdo;
        try {
            $plans = $pdo->query("SELECT plan_name FROM plans ORDER BY id ASC")->fetchAll(PDO::FETCH_COLUMN);
            sendJson(['success' => true, 'plans' => $plans]);
        } catch (Exception $e) {
            sendJson(['success' => false, 'error' => 'خطا در ارتباط با دیتابیس']);
        }
    }

    // ۲. استخراج یوزرنیم‌های مرتبط با یک طرح خاص در انبار
    if ($action === 'get_users_by_plan') {
        global $pdo;
        $planName = $_GET['plan_name'] ?? '';
        try {
            $stmt = $pdo->prepare("SELECT account_username FROM inventory WHERE plan_name = ?");
            $stmt->execute([$planName]);
            $usernames = $stmt->fetchAll(PDO::FETCH_COLUMN);
            sendJson(['success' => true, 'usernames' => $usernames]);
        } catch (Exception $e) {
            sendJson(['success' => false, 'error' => 'خطا در دریافت کاربران انبار']);
        }
    }

    // ۳. آپدیت پچ (Patch) برای ویرایش گروهی که فقط فیلدهای انتخاب شده را تغییر می‌دهد
    if ($action === 'bulk_smart_edit' && $_SERVER['REQUEST_METHOD'] === 'POST') {
        $username = trim($_POST['username'] ?? '');
        $current = executePsgApiCall($serverUrl, "/api/user/" . urlencode($username), "GET", null, $token);
        
        if ($current['code'] === 200 && isset($current['data']['username'])) {
            $userData = $current['data'];
            
            // بررسی هر فیلد، فقط اگر تیک آن خورده باشد (1 باشد) مقدار جدید جایگزین می‌شود
            if (isset($_POST['change_status']) && $_POST['change_status'] === '1') {
                $userData['status'] = trim($_POST['status']);
            }
            if (isset($_POST['change_note']) && $_POST['change_note'] === '1') {
                $userData['note'] = trim($_POST['note']);
            }
            if (isset($_POST['change_reset']) && $_POST['change_reset'] === '1') {
                $userData['data_limit_reset_strategy'] = trim($_POST['reset_strategy']);
            }
            if (isset($_POST['change_limit']) && $_POST['change_limit'] === '1') {
                $limitVal = isset($_POST['data_limit_val']) ? (float)$_POST['data_limit_val'] : (float)($_POST['data_limit_gb'] ?? 0);
                $limitUnit = $_POST['data_limit_unit'] ?? 'GB';
                $userData['data_limit'] = ($limitUnit === 'MB') ? (int)($limitVal * pow(1024, 2)) : (int)($limitVal * pow(1024, 3));
            }
            if (isset($_POST['change_expire']) && $_POST['change_expire'] === '1') {
                $expire = trim($_POST['expire_date']);
                if (empty($expire)) {
                    $userData['expire'] = null;
                } else {
                    date_default_timezone_set('Asia/Tehran');
                    $userData['expire'] = date('Y-m-d\TH:i:sP', strtotime($expire));
                }
            }
            if (isset($_POST['change_proxies']) && $_POST['change_proxies'] === '1') {
                $newProxies = [];
                if (isset($_POST['proxies']) && is_array($_POST['proxies'])) {
                    foreach ($_POST['proxies'] as $proto) {
                        $newProxies[$proto] = isset($userData['proxies'][$proto]) ? $userData['proxies'][$proto] : (($proto === 'shadowsocks') ? ["method" => "chacha20-ietf-poly1305"] : new stdClass());
                    }
                }
                $userData['proxies'] = empty($newProxies) ? new stdClass() : $newProxies;
            }
            if (isset($_POST['change_groups']) && $_POST['change_groups'] === '1') {
                if (isset($_POST['group_ids']) && is_array($_POST['group_ids'])) {
                    $userData['group_ids'] = array_map('intval', array_filter($_POST['group_ids'], 'is_numeric'));
                } else {
                    $userData['group_ids'] = [];
                }
            }

            $res = executePsgApiCall($serverUrl, "/api/user/" . urlencode($username), "PUT", $userData, $token);
            
            if ($res['code'] == 200 || $res['code'] == 201 || $res['code'] == 204) {
                sendJson(['success' => true, 'username' => $username]);
            } else {
                $errDetail = isset($res['data']['detail']) ? json_encode($res['data']['detail']) : 'خطای ذخیره‌سازی';
                sendJson(['success' => false, 'error' => $errDetail]);
            }
        } else {
            sendJson(['success' => false, 'error' => 'کاربر در سرور یافت نشد.']);
        }
    }
}
?>