<?php

declare(strict_types=1);

/**
 * Low-level HTTP client for Pasarguard API v5.
 */
class PasarguardApiClient
{
    /** @var array<string, mixed> */
    private $serverConfig;

    /** @param array<string, mixed> $serverConfig */
    public function __construct(array $serverConfig)
    {
        $this->serverConfig = $serverConfig;
    }

    /** @return object{success:bool,access_token?:string,msg?:string} */
    public function getToken()
    {
        $panelUrl = rtrim((string) ($this->serverConfig['panel_url'] ?? ''), '/');
        $curl = curl_init();
        curl_setopt_array($curl, [
            CURLOPT_URL => $panelUrl . '/api/admin/token',
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST => true,
            CURLOPT_POSTFIELDS => http_build_query([
                'username' => (string) ($this->serverConfig['username'] ?? ''),
                'password' => (string) ($this->serverConfig['password'] ?? ''),
            ]),
            CURLOPT_HTTPHEADER => [
                'Content-Type: application/x-www-form-urlencoded',
                'Accept: application/json',
            ],
            CURLOPT_CONNECTTIMEOUT => 15,
            CURLOPT_TIMEOUT => 30,
            CURLOPT_SSL_VERIFYHOST => false,
            CURLOPT_SSL_VERIFYPEER => false,
        ]);
        $raw = curl_exec($curl);
        if ($raw === false) {
            $err = curl_error($curl);
            curl_close($curl);
            return (object) ['success' => false, 'msg' => $err];
        }
        curl_close($curl);
        $json = json_decode($raw);
        if (!is_object($json) || empty($json->access_token)) {
            $msg = is_object($json) ? (string) ($json->detail ?? $json->msg ?? 'login failed') : 'login failed';
            return (object) ['success' => false, 'msg' => $msg];
        }

        return (object) ['success' => true, 'access_token' => (string) $json->access_token];
    }

    /**
     * @param array<string, mixed>|null $body
     * @return object{success:bool,status:int,data:mixed,msg?:string}
     */
    public function request(string $method, string $path, ?array $body = null, ?string $token = null)
    {
        $panelUrl = rtrim((string) ($this->serverConfig['panel_url'] ?? ''), '/');
        if ($token === null) {
            $auth = $this->getToken();
            if (!$auth->success) {
                return (object) ['success' => false, 'status' => 0, 'data' => null, 'msg' => $auth->msg ?? 'auth failed'];
            }
            $token = $auth->access_token;
        }

        $headers = [
            'Accept: application/json',
            'Authorization: Bearer ' . $token,
        ];
        $curl = curl_init();
        $options = [
            CURLOPT_URL => $panelUrl . $path,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_CUSTOMREQUEST => strtoupper($method),
            CURLOPT_HTTPHEADER => $headers,
            CURLOPT_CONNECTTIMEOUT => 15,
            CURLOPT_TIMEOUT => 45,
            CURLOPT_SSL_VERIFYHOST => false,
            CURLOPT_SSL_VERIFYPEER => false,
        ];
        if ($body !== null) {
            $options[CURLOPT_POSTFIELDS] = json_encode($body, JSON_UNESCAPED_UNICODE);
            $headers[] = 'Content-Type: application/json';
            $options[CURLOPT_HTTPHEADER] = $headers;
        }
        curl_setopt_array($curl, $options);
        $raw = curl_exec($curl);
        $status = (int) curl_getinfo($curl, CURLINFO_HTTP_CODE);
        if ($raw === false) {
            $err = curl_error($curl);
            curl_close($curl);
            return (object) ['success' => false, 'status' => 0, 'data' => null, 'msg' => $err];
        }
        curl_close($curl);

        $data = json_decode($raw);
        if ($status >= 200 && $status < 300) {
            return (object) ['success' => true, 'status' => $status, 'data' => $data];
        }

        $msg = self::formatApiError($data);

        return (object) ['success' => false, 'status' => $status, 'data' => $data, 'msg' => $msg];
    }

    /** @return string */
    private static function formatApiError($data): string
    {
        if (!is_object($data) && !is_array($data)) {
            return 'request failed';
        }
        $arr = (array) $data;
        if (isset($arr['detail'])) {
            $detail = $arr['detail'];
            if (is_string($detail)) {
                return $detail;
            }
            if (is_array($detail)) {
                return implode(' - ', array_map('strval', $detail));
            }
            if (is_object($detail)) {
                return implode(' - ', array_map('strval', (array) $detail));
            }
        }

        return (string) ($arr['msg'] ?? $arr['message'] ?? 'request failed');
    }

    /** @return array{success:bool,msg:string} */
    public static function probeConnection(string $panelUrl, string $username, string $password): array
    {
        $client = new self([
            'panel_url' => $panelUrl,
            'username' => $username,
            'password' => $password,
            'type' => 'pasarguard',
        ]);
        $auth = $client->getToken();
        if (!$auth->success) {
            return ['success' => false, 'msg' => 'Pasarguard: ' . ($auth->msg ?? 'login failed')];
        }

        return ['success' => true, 'msg' => 'اتصال Pasarguard موفق'];
    }
}
