<?php
// marzban.php
// کلاینت مرزبان بر اساس رکورد پنل از جدول vpn_panels
// پشتیبانی از هر دو حالت:
//   new MarzbanService($pdo, $panelId)
//   new MarzbanService($pdo, $panelRowArray)

class MarzbanService
{
    // به خاطر نسخه PHP، روی پراپرتی‌ها type نمی‌ذاریم
    private $pdo;
    private $baseUrl;
    private $adminUser;
    private $adminPass;
    private $token = null;

    /**
     * سازنده:
     *  - $pdo: کانکشن دیتابیس
     *  - $panelConfig:
     *      * اگر آرایه باشد ⇒ رکورد خوانده‌شده از vpn_panels
     *      * اگر عدد باشد  ⇒ id پنل در جدول vpn_panels و رکورد را خودش لود می‌کند
     *
     * ستون‌های مورد نیاز در vpn_panels:
     *  - base_url
     *  - admin_user
     *  - admin_pass
     */
    public function __construct($pdo, $panelConfig)
    {
        $this->pdo = $pdo;

        // 1) تشخیص نوع ورودی: آرایه رکورد یا id پنل
        if (is_array($panelConfig)) {
            // مستقیماً رکورد پنل داده شده
            $panelRow = $panelConfig;
        } else {
            // فرض می‌کنیم id پنل است و باید از دیتابیس بخوانیم
            $panelId = (int)$panelConfig;

            if ($panelId <= 0) {
                throw new Exception('شناسه پنل مرزبان نامعتبر است.');
            }
            if (!$this->pdo) {
                throw new Exception('اتصال دیتابیس برای دریافت اطلاعات پنل در دسترس نیست.');
            }

            $stmt = $this->pdo->prepare("SELECT * FROM vpn_panels WHERE id = :id LIMIT 1");
            $stmt->execute([':id' => $panelId]);
            $panelRow = $stmt->fetch(PDO::FETCH_ASSOC);

            if (!$panelRow) {
                throw new Exception('پنل مرزبان با این شناسه در جدول vpn_panels پیدا نشد.');
            }
        }

        // 2) تنظیم مقادیر از رکورد پنل
        $this->baseUrl   = rtrim((string)($panelRow['base_url']   ?? ''), '/');
        $this->adminUser = (string)($panelRow['admin_user'] ?? '');
        $this->adminPass = (string)($panelRow['admin_pass'] ?? '');

        if ($this->baseUrl === '' || $this->adminUser === '' || $this->adminPass === '') {
            throw new Exception('تنظیمات پنل مرزبان (base_url / admin_user / admin_pass) ناقص است.');
        }
    }

    public function getBaseUrl(): string
    {
        return $this->baseUrl;
    }

    /**
     * گرفتن توکن ادمین از مرزبان
     */
    private function getToken(): string
    {
        if ($this->token !== null) {
            return $this->token;
        }

        $url = $this->baseUrl . '/api/admin/token';

        $postFields = http_build_query([
            'grant_type'    => 'password',
            'username'      => $this->adminUser,
            'password'      => $this->adminPass,
            'scope'         => '',
            'client_id'     => 'string',
            'client_secret' => 'string',
        ], '', '&');

        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST           => true,
            CURLOPT_HTTPHEADER     => [
                'accept: application/json',
                'Content-Type: application/x-www-form-urlencoded',
            ],
            CURLOPT_POSTFIELDS     => $postFields,
            CURLOPT_TIMEOUT        => 30,
        ]);
        $resp = curl_exec($ch);
        $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $err  = curl_error($ch);
        curl_close($ch);

        if ($code !== 200) {
            error_log("MB_TOKEN_FAIL code=$code err=$err resp=$resp");
            throw new Exception('گرفتن توکن از سرور مرزبان ناموفق بود.');
        }

        $js = json_decode($resp, true);
        if (!is_array($js) || empty($js['access_token'])) {
            error_log("MB_TOKEN_BAD resp=$resp");
            throw new Exception('توکن دریافتی از مرزبان معتبر نبود.');
        }

        $this->token = $js['access_token'];
        return $this->token;
    }

    /**
     * متد عمومی برای زدن درخواست به API مرزبان
     */
    private function call(string $method, string $path, ?array $body = null): array
    {
        $token = $this->getToken();

        $url = $this->baseUrl . $path;

        $headers = [
            'Accept: application/json',
            'Authorization: Bearer ' . $token,
        ];

        $opts = [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_CUSTOMREQUEST  => $method,
            CURLOPT_TIMEOUT        => 30,
            CURLOPT_HTTPHEADER     => $headers,
        ];

        if ($body !== null) {
            $opts[CURLOPT_HTTPHEADER][] = 'Content-Type: application/json';
            $opts[CURLOPT_POSTFIELDS]   = json_encode($body, JSON_UNESCAPED_UNICODE);
        }

        $ch = curl_init($url);
        curl_setopt_array($ch, $opts);
        $resp = curl_exec($ch);
        $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $err  = curl_error($ch);
        curl_close($ch);

        $json = null;
        if ($resp !== false) {
            $json = json_decode($resp, true);
        }

        return [
            'code' => (int)$code,
            'err'  => $err,
            'raw'  => $resp,
            'json' => $json,
        ];
    }

    /**
     * ساخت یوزر جدید
     */
    public function createUser(array $payload): array
    {
        return $this->call('POST', '/api/user', $payload);
    }

    /**
     * گرفتن اطلاعات کاربر
     */
    public function getUser(string $username): array
    {
        $path = '/api/user/' . rawurlencode($username);
        return $this->call('GET', $path, null);
    }

    /**
     * آپدیت یوزر (برای تمدید)
     */
    public function renewUser(string $username, array $payload): array
    {
        $path = '/api/user/' . rawurlencode($username);
        return $this->call('PUT', $path, $payload);
    }

    /**
     * ریست ترافیک بعد از تمدید
     */
    public function resetTraffic(string $username): array
    {
        $path = '/api/user/' . rawurlencode($username) . '/reset';
        return $this->call('POST', $path, []);
    }
}
