<?php
/**
 * AYCore PasarGuard v5 adapter
 *
 * Uses PasarGuard's public REST API. The adapter intentionally keeps
 * authentication and payload normalization in one place so future endpoint
 * changes do not leak through the rest of iTzAYDiN-BOT.
 */

if (!function_exists('pg_normalize_base_url')) {
    function pg_normalize_base_url(string $url): string
    {
        $url = trim($url);
        if ($url === '') return '';
        if (!preg_match('~^https?://~i', $url)) $url = 'https://' . ltrim($url, '/');
        $parts = @parse_url($url);
        if (!is_array($parts) || empty($parts['host'])) return rtrim($url, '/');
        $scheme = strtolower((string)($parts['scheme'] ?? 'https'));
        $host = (string)$parts['host'];
        $port = isset($parts['port']) ? ':' . (int)$parts['port'] : '';
        $path = rtrim((string)($parts['path'] ?? ''), '/');
        // Common frontend/docs paths are not API prefixes. If an admin copies the
        // browser URL from one of these pages, normalize it back to the panel origin.
        $uiSuffixes = ['/dashboard', '/login', '/admin', '/docs', '/redoc', '/api'];
        foreach ($uiSuffixes as $suffix) {
            if (strcasecmp($path, $suffix) === 0) { $path = ''; break; }
        }
        return rtrim($scheme . '://' . $host . $port . $path, '/');
    }
}

if (!function_exists('pg_base_url')) {
    function pg_base_url(array $panel): string
    {
        $api = trim((string)($panel['pg_api_url'] ?? ''));
        $ui  = trim((string)($panel['url_panel'] ?? ''));
        return pg_normalize_base_url($api !== '' ? $api : $ui);
    }
}

if (!function_exists('pg_panel_url')) {
    function pg_panel_url(array $panel): string
    {
        return pg_normalize_base_url((string)($panel['url_panel'] ?? ''));
    }
}

if (!function_exists('pg_json')) {
    function pg_json($value, $default = [])
    {
        if (is_array($value)) return $value;
        if ($value === null || $value === '') return $default;
        $decoded = json_decode((string)$value, true);
        return is_array($decoded) ? $decoded : $default;
    }
}

if (!function_exists('pg_is_cloudflare_challenge')) {
    function pg_is_cloudflare_challenge(array $response): bool
    {
        $raw = strtolower((string)($response['raw'] ?? ''));
        $headers = array_change_key_case((array)($response['response_headers'] ?? []), CASE_LOWER);
        $server = strtolower((string)($headers['server'] ?? ''));
        if (strpos($raw, '/cdn-cgi/challenge-platform/') !== false) return true;
        if (strpos($raw, '__cf$cv$params') !== false) return true;
        if (strpos($raw, 'cf-chl-') !== false || strpos($raw, 'challenge-form') !== false) return true;
        if (strpos($server, 'cloudflare') !== false && strpos((string)($response['content_type'] ?? ''), 'text/html') !== false && in_array((int)($response['http_code'] ?? 0), [403, 429, 503], true)) return true;
        return false;
    }
}

if (!function_exists('pg_is_html_response')) {
    function pg_is_html_response(array $response): bool
    {
        $ct = strtolower((string)($response['content_type'] ?? ''));
        $raw = ltrim((string)($response['raw'] ?? ''));
        return strpos($ct, 'text/html') !== false || stripos($raw, '<!doctype html') === 0 || stripos($raw, '<html') === 0;
    }
}

if (!function_exists('pg_error_message')) {
    function pg_error_message(array $response): string
    {
        if (pg_is_cloudflare_challenge($response)) {
            return 'Cloudflare Challenge جلوی API پاسارگارد را گرفته است. درخواست ربات به جای JSON صفحه Challenge گرفته. برای مسیر /api/* در Cloudflare قانون Skip/Allow بساز یا یک API Endpoint مستقیم/DNS-only برای پنل تعریف کن و آن را در فیلد «API Endpoint» ربات وارد کن.';
        }
        $body = $response['json'] ?? null;
        if (is_array($body)) {
            foreach (['detail', 'message', 'error', 'msg'] as $key) {
                if (!empty($body[$key])) {
                    if (is_array($body[$key])) return json_encode($body[$key], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
                    return (string)$body[$key];
                }
            }
        }
        if (!empty($response['curl_error'])) return (string)$response['curl_error'];
        $status = (int)($response['http_code'] ?? 0);
        $effective = trim((string)($response['effective_url'] ?? ''));
        if ($status === 405) {
            return 'PasarGuard پاسخ Method Not Allowed داد. معمولاً URL پنل به صفحه Dashboard/Login یا مسیر اشتباه اشاره می‌کند، یا Reverse Proxy درخواست API را به Frontend می‌فرستد.' . ($effective !== '' ? ' URL نهایی: ' . $effective : '');
        }
        if (pg_is_html_response($response)) {
            return 'API پاسارگارد به جای JSON یک صفحه HTML برگرداند (HTTP ' . $status . '). URL/API Endpoint یا تنظیم Reverse Proxy/Cloudflare را بررسی کن.' . ($effective !== '' ? ' URL نهایی: ' . $effective : '');
        }
        if (!empty($response['raw'])) return mb_substr(strip_tags((string)$response['raw']), 0, 700, 'UTF-8');
        return 'PasarGuard API returned HTTP ' . $status . ($effective !== '' ? ' · ' . $effective : '');
    }
}

if (!function_exists('pg_http')) {
    function pg_http(string $url, string $method = 'GET', array $headers = [], $payload = null, bool $form = false): array
    {
        if (!function_exists('curl_init')) {
            return ['ok' => false, 'http_code' => 0, 'curl_errno' => -1, 'curl_error' => 'PHP cURL extension is not installed.', 'raw' => '', 'json' => null, 'response_headers' => []];
        }
        $responseHeaders = [];
        $ch = curl_init($url);
        $headers[] = 'Accept: application/json';
        $options = [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_CUSTOMREQUEST => strtoupper($method),
            CURLOPT_HTTPHEADER => $headers,
            CURLOPT_CONNECTTIMEOUT => 7,
            CURLOPT_TIMEOUT => 20,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_MAXREDIRS => 3,
            CURLOPT_USERAGENT => 'iTzAYDiN-BOT/8.1 PasarGuardAdapter',
            CURLOPT_ENCODING => '',
            CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
            CURLOPT_HEADERFUNCTION => static function ($ch, string $line) use (&$responseHeaders): int {
                $len = strlen($line);
                $line = trim($line);
                if ($line === '' || strpos($line, ':') === false) return $len;
                [$name, $value] = array_map('trim', explode(':', $line, 2));
                $responseHeaders[strtolower($name)] = $value;
                return $len;
            },
        ];
        if (defined('CURLOPT_POSTREDIR')) $options[CURLOPT_POSTREDIR] = CURL_REDIR_POST_ALL;
        if ($payload !== null) {
            if ($form) {
                $options[CURLOPT_POSTFIELDS] = http_build_query($payload, '', '&', PHP_QUERY_RFC3986);
                $options[CURLOPT_HTTPHEADER][] = 'Content-Type: application/x-www-form-urlencoded';
            } else {
                $options[CURLOPT_POSTFIELDS] = json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
                $options[CURLOPT_HTTPHEADER][] = 'Content-Type: application/json';
            }
        }
        curl_setopt_array($ch, $options);
        $raw = curl_exec($ch);
        $errno = curl_errno($ch);
        $error = curl_error($ch);
        $status = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $effective = (string)curl_getinfo($ch, CURLINFO_EFFECTIVE_URL);
        $contentType = (string)curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
        $redirectCount = (int)curl_getinfo($ch, CURLINFO_REDIRECT_COUNT);
        curl_close($ch);
        $rawString = $raw === false ? '' : (string)$raw;
        $decoded = $rawString !== '' ? json_decode($rawString, true) : null;
        return [
            'ok' => $errno === 0 && $status >= 200 && $status < 300 && is_array($decoded),
            'http_code' => $status,
            'curl_errno' => $errno,
            'curl_error' => $error,
            'raw' => $rawString,
            'json' => is_array($decoded) ? $decoded : null,
            'effective_url' => $effective,
            'content_type' => $contentType,
            'redirect_count' => $redirectCount,
            'response_headers' => $responseHeaders,
        ];
    }
}

if (!function_exists('pg_login')) {
    function pg_login(array $panel, bool $force = false): array
    {
        $base = pg_base_url($panel);
        if ($base === '') return ['ok' => false, 'error' => 'آدرس PasarGuard خالی است.'];

        $authMode = strtolower(trim((string)($panel['pg_auth_mode'] ?? 'password')));
        $directToken = trim((string)($panel['pg_access_token'] ?? ''));
        if (in_array($authMode, ['bearer', 'token'], true) && $directToken !== '') {
            return ['ok' => true, 'token' => $directToken, 'source' => 'stored_bearer'];
        }

        static $memory = [];
        $cacheKey = sha1(($panel['code_panel'] ?? $panel['name_panel'] ?? '') . '|' . ($panel['username_panel'] ?? ''));
        if (!$force && isset($memory[$cacheKey]) && ($memory[$cacheKey]['until'] ?? 0) > time()) {
            return ['ok' => true, 'token' => $memory[$cacheKey]['token'], 'source' => 'memory'];
        }

        $username = trim((string)($panel['username_panel'] ?? ''));
        $password = (string)($panel['password_panel'] ?? '');
        if ($username === '' || $password === '') {
            return ['ok' => false, 'error' => 'نام کاربری/رمز مدیریت PasarGuard تنظیم نشده است.'];
        }
        $response = pg_http($base . '/api/admin/token', 'POST', [], [
            'username' => $username,
            'password' => $password,
            'grant_type' => 'password',
        ], true);
        $token = trim((string)($response['json']['access_token'] ?? ''));
        if (!$response['ok'] || $token === '') {
            return ['ok' => false, 'error' => pg_error_message($response), 'response' => $response];
        }
        $memory[$cacheKey] = ['token' => $token, 'until' => time() + 900];
        return ['ok' => true, 'token' => $token, 'source' => 'password'];
    }
}

if (!function_exists('pg_auth_context')) {
    function pg_auth_context(array $panel, bool $force = false): array
    {
        $mode = strtolower(trim((string)($panel['pg_auth_mode'] ?? 'password')));
        if (in_array($mode, ['api_key', 'apikey', 'api-key'], true)) {
            $key = trim((string)($panel['pg_api_key'] ?? ''));
            // Compatibility: early V5 builds reused pg_access_token for direct credentials.
            if ($key === '') $key = trim((string)($panel['pg_access_token'] ?? ''));
            if ($key === '') return ['ok' => false, 'error' => 'API Key پاسارگارد تنظیم نشده است.'];
            return ['ok' => true, 'headers' => ['X-Api-Key: ' . $key, 'Authorization: ApiKey ' . $key], 'source' => 'api_key'];
        }

        $auth = pg_login($panel, $force);
        if (empty($auth['ok'])) return $auth;
        return [
            'ok' => true,
            'headers' => ['Authorization: Bearer ' . $auth['token']],
            'source' => $auth['source'] ?? 'password',
        ];
    }
}

if (!function_exists('pg_request')) {
    function pg_request(array $panel, string $method, string $path, $payload = null, bool $retryAuth = true): array
    {
        $auth = pg_auth_context($panel, false);
        if (empty($auth['ok'])) {
            return ['ok' => false, 'http_code' => 0, 'json' => null, 'raw' => '', 'curl_errno' => 0, 'curl_error' => $auth['error'] ?? 'PasarGuard authentication failed'];
        }
        $response = pg_http(
            pg_base_url($panel) . '/' . ltrim($path, '/'),
            $method,
            $auth['headers'] ?? [],
            $payload,
            false
        );
        // API keys and direct bearer tokens cannot be transparently refreshed.
        if ($response['http_code'] === 401 && $retryAuth && (($auth['source'] ?? '') === 'password' || ($auth['source'] ?? '') === 'memory')) {
            $fresh = pg_auth_context($panel, true);
            if (!empty($fresh['ok'])) {
                return pg_http(
                    pg_base_url($panel) . '/' . ltrim($path, '/'),
                    $method,
                    $fresh['headers'] ?? [],
                    $payload,
                    false
                );
            }
        }
        return $response;
    }
}

if (!function_exists('pg_test_connection')) {
    function pg_test_connection(array $panel): array
    {
        $r = pg_request($panel, 'GET', '/api/admin');
        if ($r['ok']) {
            return [
                'ok' => true,
                'admin' => $r['json'],
                'message' => 'اتصال PasarGuard برقرار است.',
                'api_url' => pg_base_url($panel),
                'http_code' => $r['http_code'] ?? 200,
            ];
        }
        return [
            'ok' => false,
            'message' => pg_error_message($r),
            'http_code' => $r['http_code'] ?? 0,
            'api_url' => pg_base_url($panel),
            'effective_url' => $r['effective_url'] ?? '',
            'cloudflare_challenge' => pg_is_cloudflare_challenge($r),
            'html_response' => pg_is_html_response($r),
            'curl_errno' => $r['curl_errno'] ?? 0,
        ];
    }
}

if (!function_exists('pg_extract_collection')) {
    /**
     * PasarGuard list endpoints have changed envelope names across releases.
     * Normalize common response shapes without forcing the rest of the bot to care.
     */
    function pg_extract_collection($json, array $keys = []): array
    {
        if (!is_array($json)) return [];
        foreach ($keys as $key) {
            if (isset($json[$key]) && is_array($json[$key])) return array_values($json[$key]);
        }
        foreach (['items','results','data'] as $key) {
            if (isset($json[$key]) && is_array($json[$key])) {
                $value = $json[$key];
                foreach ($keys as $nestedKey) {
                    if (isset($value[$nestedKey]) && is_array($value[$nestedKey])) return array_values($value[$nestedKey]);
                }
                if (array_is_list($value)) return array_values($value);
            }
        }
        return array_is_list($json) ? array_values($json) : [];
    }
}

if (!function_exists('pg_create_api_key')) {
    function pg_create_api_key(array $panel, string $name = 'iTzAYDiN-BOT', ?string $expireDate = null): array
    {
        $payload = [
            'name' => trim($name) !== '' ? trim($name) : 'iTzAYDiN-BOT',
            'note' => 'Provisioned by iTzAYDiN-BOT / iTz PasarGuard Hub',
            'inherit_permissions' => true,
        ];
        if ($expireDate !== null && trim($expireDate) !== '') $payload['expire_date'] = trim($expireDate);
        $r = pg_request($panel, 'POST', '/api/api_key', $payload);
        if (!$r['ok']) return ['ok' => false, 'error' => pg_error_message($r), 'response' => $r];
        $raw = trim((string)($r['json']['api_key'] ?? ''));
        if ($raw === '') return ['ok' => false, 'error' => 'PasarGuard API Key ساخته شد اما کلید خام در پاسخ موجود نبود.', 'response' => $r];
        return ['ok' => true, 'api_key' => $raw, 'meta' => $r['json']];
    }
}

if (!function_exists('pg_list_api_keys')) {
    function pg_list_api_keys(array $panel, int $limit = 100): array
    {
        $r = pg_request($panel, 'GET', '/api/api_keys?limit=' . max(1, min(200, $limit)));
        if (!$r['ok']) return ['ok' => false, 'error' => pg_error_message($r), 'api_keys' => []];
        return ['ok' => true, 'api_keys' => pg_extract_collection($r['json'] ?? [], ['api_keys','keys']), 'meta' => $r['json']];
    }
}

if (!function_exists('pg_revoke_api_key')) {
    function pg_revoke_api_key(array $panel, int $keyId): array
    {
        if ($keyId <= 0) return ['ok' => false, 'error' => 'API Key ID نامعتبر است.'];
        $r = pg_request($panel, 'POST', '/api/api_key/' . $keyId . '/revoke');
        return $r['ok'] ? ['ok' => true, 'result' => $r['json']] : ['ok' => false, 'error' => pg_error_message($r)];
    }
}

if (!function_exists('pg_get_user')) {
    function pg_get_user(array $panel, string $username): array
    {
        $r = pg_request($panel, 'GET', '/api/user/by-username/' . rawurlencode($username));
        if (!$r['ok']) return ['ok' => false, 'error' => pg_error_message($r), 'response' => $r];
        return ['ok' => true, 'user' => $r['json']];
    }
}

if (!function_exists('pg_user_id')) {
    function pg_user_id(array $panel, string $username): array
    {
        $u = pg_get_user($panel, $username);
        if (empty($u['ok'])) return $u;
        $id = (int)($u['user']['id'] ?? 0);
        if ($id <= 0) return ['ok' => false, 'error' => 'PasarGuard user ID was not returned.'];
        return ['ok' => true, 'id' => $id, 'user' => $u['user']];
    }
}

if (!function_exists('pg_iso_expire')) {
    function pg_iso_expire($timestamp)
    {
        $timestamp = (int)$timestamp;
        if ($timestamp <= 0) return 0;
        return gmdate('Y-m-d\TH:i:s\Z', $timestamp);
    }
}

if (!function_exists('pg_create_user')) {
    function pg_create_user(array $panel, string $username, int $dataLimit, int $expire, string $note = '', array $product = []): array
    {
        $groups = pg_json($product['pg_group_ids'] ?? ($panel['pg_group_ids'] ?? ''), []);
        $proxies = pg_json($product['pg_proxy_settings'] ?? ($panel['pg_proxy_settings'] ?? ''), []);
        $payload = [
            'username' => $username,
            'status' => 'active',
            'expire' => pg_iso_expire($expire),
            'data_limit' => max(0, $dataLimit),
            'data_limit_reset_strategy' => (string)($product['data_limit_reset'] ?? 'no_reset'),
            'note' => mb_substr($note, 0, 500, 'UTF-8'),
        ];
        if (!empty($groups)) $payload['group_ids'] = array_values(array_unique(array_map('intval', $groups)));
        if (!empty($proxies)) $payload['proxy_settings'] = $proxies;
        $r = pg_request($panel, 'POST', '/api/user', $payload);
        if (!$r['ok']) return ['ok' => false, 'error' => pg_error_message($r), 'response' => $r];
        return ['ok' => true, 'user' => $r['json']];
    }
}

if (!function_exists('pg_modify_user')) {
    function pg_modify_user(array $panel, string $username, array $changes): array
    {
        $resolved = pg_user_id($panel, $username);
        if (empty($resolved['ok'])) return $resolved;
        $r = pg_request($panel, 'PUT', '/api/user/by-id/' . $resolved['id'], $changes);
        if (!$r['ok']) return ['ok' => false, 'error' => pg_error_message($r), 'response' => $r];
        return ['ok' => true, 'user' => $r['json']];
    }
}

if (!function_exists('pg_toggle_user')) {
    function pg_toggle_user(array $panel, string $username, bool $disabled): array
    {
        $resolved = pg_user_id($panel, $username);
        if (empty($resolved['ok'])) return $resolved;
        $r = pg_request($panel, 'PUT', '/api/user/by-id/' . $resolved['id'] . '/disabled', ['disabled' => $disabled]);
        return $r['ok'] ? ['ok' => true, 'user' => $r['json']] : ['ok' => false, 'error' => pg_error_message($r)];
    }
}

if (!function_exists('pg_delete_user')) {
    function pg_delete_user(array $panel, string $username): array
    {
        $resolved = pg_user_id($panel, $username);
        if (empty($resolved['ok'])) return $resolved;
        $r = pg_request($panel, 'DELETE', '/api/user/by-id/' . $resolved['id']);
        return $r['ok'] ? ['ok' => true] : ['ok' => false, 'error' => pg_error_message($r)];
    }
}

if (!function_exists('pg_reset_user')) {
    function pg_reset_user(array $panel, string $username): array
    {
        $resolved = pg_user_id($panel, $username);
        if (empty($resolved['ok'])) return $resolved;
        $r = pg_request($panel, 'POST', '/api/user/by-id/' . $resolved['id'] . '/reset');
        return $r['ok'] ? ['ok' => true, 'user' => $r['json']] : ['ok' => false, 'error' => pg_error_message($r)];
    }
}

if (!function_exists('pg_revoke_user')) {
    function pg_revoke_user(array $panel, string $username): array
    {
        $resolved = pg_user_id($panel, $username);
        if (empty($resolved['ok'])) return $resolved;
        $r = pg_request($panel, 'POST', '/api/user/by-id/' . $resolved['id'] . '/revoke_sub');
        return $r['ok'] ? ['ok' => true, 'user' => $r['json']] : ['ok' => false, 'error' => pg_error_message($r)];
    }
}

if (!function_exists('pg_list_roles')) {
    function pg_list_roles(array $panel): array
    {
        $r = pg_request($panel, 'GET', '/api/admin-roles/simple');
        if (!$r['ok']) return ['ok' => false, 'error' => pg_error_message($r), 'roles' => []];
        $json = $r['json'] ?? [];
        $roles = pg_extract_collection($json, ['roles','admin_roles']);
        return ['ok' => true, 'roles' => $roles];
    }
}

if (!function_exists('pg_create_reseller_admin')) {
    function pg_create_reseller_admin(array $panel, string $username, string $password, array $options = []): array
    {
        $roleId = (int)($options['role_id'] ?? ($panel['pg_default_role_id'] ?? 0));
        if ($roleId <= 0) return ['ok' => false, 'error' => 'برای محصول نمایندگی PasarGuard یک Role ID معتبر انتخاب نشده است.'];
        $payload = [
            'username' => $username,
            'password' => $password,
            'role_id' => $roleId,
            'status' => 'active',
        ];
        if (array_key_exists('data_limit', $options) && $options['data_limit'] !== '') $payload['data_limit'] = max(0, (int)$options['data_limit']);
        if (!empty($options['sub_domain'])) $payload['sub_domain'] = (string)$options['sub_domain'];
        if (!empty($options['profile_title'])) $payload['profile_title'] = (string)$options['profile_title'];
        if (!empty($options['support_url'])) $payload['support_url'] = (string)$options['support_url'];
        if (!empty($options['note'])) $payload['note'] = mb_substr((string)$options['note'], 0, 500, 'UTF-8');
        if (!empty($options['permission_overrides']) && is_array($options['permission_overrides'])) {
            $payload['permission_overrides'] = $options['permission_overrides'];
        }
        $r = pg_request($panel, 'POST', '/api/admin', $payload);
        if (!$r['ok']) return ['ok' => false, 'error' => pg_error_message($r), 'response' => $r];
        return ['ok' => true, 'admin' => $r['json']];
    }
}

if (!function_exists('pg_get_admins')) {
    function pg_get_admins(array $panel, int $limit = 100): array
    {
        $r = pg_request($panel, 'GET', '/api/admins?limit=' . max(1, min(500, $limit)));
        if (!$r['ok']) return ['ok' => false, 'error' => pg_error_message($r), 'admins' => []];
        return ['ok' => true, 'admins' => pg_extract_collection($r['json'] ?? [], ['admins']), 'meta' => $r['json']];
    }
}

if (!function_exists('pg_modify_admin')) {
    function pg_modify_admin(array $panel, int $adminId, array $changes): array
    {
        $r = pg_request($panel, 'PUT', '/api/admin/by-id/' . $adminId, $changes);
        return $r['ok'] ? ['ok' => true, 'admin' => $r['json']] : ['ok' => false, 'error' => pg_error_message($r)];
    }
}

if (!function_exists('pg_delete_admin')) {
    function pg_delete_admin(array $panel, int $adminId): array
    {
        $r = pg_request($panel, 'DELETE', '/api/admin/by-id/' . $adminId);
        return $r['ok'] ? ['ok' => true] : ['ok' => false, 'error' => pg_error_message($r)];
    }
}

if (!function_exists('pg_random_password')) {
    function pg_random_password(int $length = 18): string
    {
        $length = max(12, min(64, $length));
        $alphabet = 'ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz23456789!@#-_';
        $max = strlen($alphabet) - 1;
        $out = '';
        for ($i = 0; $i < $length; $i++) $out .= $alphabet[random_int(0, $max)];
        return $out;
    }
}

if (!function_exists('pg_reset_admin_usage')) {
    function pg_reset_admin_usage(array $panel, int $adminId): array
    {
        if ($adminId <= 0) return ['ok' => false, 'error' => 'Admin ID نامعتبر است.'];
        $r = pg_request($panel, 'POST', '/api/admin/by-id/' . $adminId . '/reset');
        return $r['ok'] ? ['ok' => true, 'admin' => $r['json']] : ['ok' => false, 'error' => pg_error_message($r)];
    }
}

if (!function_exists('pg_set_admin_status')) {
    function pg_set_admin_status(array $panel, int $adminId, string $status): array
    {
        if ($adminId <= 0) return ['ok' => false, 'error' => 'Admin ID نامعتبر است.'];
        $status = strtolower(trim($status));
        if (!in_array($status, ['active', 'disabled', 'limited'], true)) {
            return ['ok' => false, 'error' => 'وضعیت نمایندگی معتبر نیست.'];
        }
        return pg_modify_admin($panel, $adminId, ['status' => $status]);
    }
}

if (!function_exists('pg_admin_users_action')) {
    function pg_admin_users_action(array $panel, int $adminId, string $action): array
    {
        if ($adminId <= 0) return ['ok' => false, 'error' => 'Admin ID نامعتبر است.'];
        $action = strtolower(trim($action));
        if ($action === 'disable') {
            $r = pg_request($panel, 'POST', '/api/admin/by-id/' . $adminId . '/users/disable');
        } elseif ($action === 'activate' || $action === 'enable') {
            $r = pg_request($panel, 'POST', '/api/admin/by-id/' . $adminId . '/users/activate');
        } elseif ($action === 'delete') {
            $r = pg_request($panel, 'DELETE', '/api/admin/by-id/' . $adminId . '/users');
        } else {
            return ['ok' => false, 'error' => 'عملیات کاربران نمایندگی نامعتبر است.'];
        }
        return $r['ok'] ? ['ok' => true, 'result' => $r['json']] : ['ok' => false, 'error' => pg_error_message($r)];
    }
}

if (!function_exists('pg_get_admin_usage')) {
    function pg_get_admin_usage(array $panel, int $adminId, array $query = []): array
    {
        if ($adminId <= 0) return ['ok' => false, 'error' => 'Admin ID نامعتبر است.', 'usage' => []];
        $qs = $query ? ('?' . http_build_query($query, '', '&', PHP_QUERY_RFC3986)) : '';
        $r = pg_request($panel, 'GET', '/api/admin/by-id/' . $adminId . '/usage' . $qs);
        return $r['ok'] ? ['ok' => true, 'usage' => $r['json']] : ['ok' => false, 'error' => pg_error_message($r), 'usage' => []];
    }
}

if (!function_exists('pg_bulk_admin_action')) {
    function pg_bulk_admin_action(array $panel, array $adminIds, string $action): array
    {
        $ids = array_values(array_unique(array_filter(array_map('intval', $adminIds), static fn($v) => $v > 0)));
        if (!$ids) return ['ok' => false, 'error' => 'هیچ Admin ID معتبری انتخاب نشده است.'];
        $map = [
            'reset' => ['POST', '/api/admins/bulk/reset'],
            'disable' => ['POST', '/api/admins/bulk/disable'],
            'enable' => ['POST', '/api/admins/bulk/enable'],
            'delete' => ['POST', '/api/admins/bulk/delete'],
            'users_disable' => ['POST', '/api/admins/bulk/users/disable'],
            'users_activate' => ['POST', '/api/admins/bulk/users/activate'],
            'users_delete' => ['DELETE', '/api/admins/bulk/users'],
        ];
        if (!isset($map[$action])) return ['ok' => false, 'error' => 'Bulk action نامعتبر است.'];
        [$method, $path] = $map[$action];
        // PasarGuard's BulkAdminSelection model currently accepts admin_ids.
        $r = pg_request($panel, $method, $path, ['admin_ids' => $ids]);
        return $r['ok'] ? ['ok' => true, 'result' => $r['json']] : ['ok' => false, 'error' => pg_error_message($r)];
    }
}
