<?php

declare(strict_types=1);

require_once __DIR__ . '/PasarguardApiClient.php';
require_once __DIR__ . '/PasarguardConfig.php';

/**
 * High-level Pasarguard user operations for the bot.
 */
class PasarguardService
{
    /** @var PasarguardApiClient */
    private $client;

    /** @var array<string, mixed> */
    private $serverConfig;

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

    /** @return object{success:bool,msg?:string,sub_link?:string,vray_links?:string[]} */
    public function createUser(string $remark, int $volumeGb, int $days, array $planSettings)
    {
        unset($volumeGb, $days);
        $templateId = (int) ($planSettings['template_id'] ?? 0);
        if ($templateId <= 0) {
            return (object) ['success' => false, 'msg' => 'User Template برای این پلن انتخاب نشده'];
        }

        $response = $this->client->request('POST', '/api/user/from_template', [
            'user_template_id' => $templateId,
            'username' => $remark,
        ]);

        if (!$response->success) {
            $msg = strtolower((string) ($response->msg ?? ''));
            if (strpos($msg, 'exist') !== false || strpos($msg, 'already') !== false || strpos($msg, 'duplicate') !== false) {
                $existing = $this->getUser($remark);
                if ($existing) {
                    return $this->buildCreateResponse($existing);
                }
            }
            return (object) ['success' => false, 'msg' => $response->msg ?? 'create failed'];
        }

        return $this->buildCreateResponse($response->data, (string) $remark);
    }

    /** @return object|null */
    public function getUser(string $remark)
    {
        $path = '/api/user/' . rawurlencode($remark);
        $response = $this->client->request('GET', $path);
        if (!$response->success) {
            return null;
        }

        return is_object($response->data) ? $response->data : null;
    }

    /** @param array<string, mixed> $info @return object{success:bool,msg?:string} */
    public function editUser(string $remark, array $info)
    {
        $configInfo = $this->getUser($remark);
        if (!$configInfo) {
            return (object) ['success' => false, 'msg' => 'User not found'];
        }

        $expireTime = (int) ($configInfo->expire ?? 0);
        $volume = (int) ($configInfo->data_limit ?? 0);

        if (isset($info['plus_day'])) {
            if ($expireTime < time()) {
                $expireTime = time() + (86400 * (int) $info['plus_day']);
            } else {
                $expireTime += (86400 * (int) $info['plus_day']);
            }
        } elseif (isset($info['days'])) {
            $expireTime = time() + (86400 * (int) $info['days']);
        }

        if (isset($info['plus_volume'])) {
            $volume += (int) $info['plus_volume'] * 1073741824;
        } elseif (isset($info['volume'])) {
            $volume = (int) $info['volume'] * 1073741824;
            $reset = $this->resetTraffic($remark);
            if (!$reset->success) {
                return $reset;
            }
        }

        $payload = [
            'expire' => $expireTime > 0 ? $expireTime : null,
            'data_limit' => $volume > 0 ? $volume : null,
            'status' => 'active',
        ];

        $response = $this->client->request('PUT', '/api/user/' . rawurlencode($remark), $payload);
        if (!$response->success) {
            return (object) ['success' => false, 'msg' => $response->msg ?? 'update failed'];
        }

        return (object) ['success' => true];
    }

    /** @return object{success:bool,msg?:string} */
    public function deleteUser(string $remark)
    {
        $response = $this->client->request('DELETE', '/api/user/' . rawurlencode($remark));
        if (!$response->success) {
            return (object) ['success' => false, 'msg' => $response->msg ?? 'delete failed'];
        }

        return (object) ['success' => true];
    }

    /** @return object{success:bool,msg?:string} */
    public function resetTraffic(string $remark)
    {
        $response = $this->client->request('POST', '/api/user/' . rawurlencode($remark) . '/reset');
        if (!$response->success) {
            return (object) ['success' => false, 'msg' => $response->msg ?? 'reset failed'];
        }

        return (object) ['success' => true];
    }

    /** @return object{success:bool,msg?:string,subscription_url?:string,links?:string[]} */
    public function revokeSubscription(string $remark)
    {
        $response = $this->client->request('POST', '/api/user/' . rawurlencode($remark) . '/revoke_sub');
        if (!$response->success) {
            return (object) ['success' => false, 'msg' => $response->msg ?? 'revoke failed'];
        }
        $user = $this->getUser($remark);
        if (!$user) {
            return (object) ['success' => false, 'msg' => 'User not found after revoke'];
        }

        $panelUrl = (string) ($this->serverConfig['panel_url'] ?? '');
        $subUrl = PasarguardConfig::buildSubscriptionUrl($panelUrl, (string) ($user->subscription_url ?? ''));

        return (object) [
            'success' => true,
            'subscription_url' => (string) ($user->subscription_url ?? ''),
            'links' => $subUrl !== '' ? [$subUrl] : [],
        ];
    }

    /** @return object{success:bool,msg?:string} */
    public function toggleState(string $remark)
    {
        $configInfo = $this->getUser($remark);
        if (!$configInfo) {
            return (object) ['success' => false, 'msg' => 'User not found'];
        }
        $newStatus = ($configInfo->status ?? '') === 'active' ? 'disabled' : 'active';
        $response = $this->client->request('PUT', '/api/user/' . rawurlencode($remark), [
            'status' => $newStatus,
        ]);
        if (!$response->success) {
            return (object) ['success' => false, 'msg' => $response->msg ?? 'toggle failed'];
        }

        return (object) ['success' => true];
    }

    /** @return array<int, object{id:int,name:?string}> */
    public function listUserTemplates(): array
    {
        $response = $this->client->request('GET', '/api/user_templates/simple');
        if (!$response->success || !is_object($response->data)) {
            return [];
        }
        $templates = $response->data->templates ?? [];

        return is_array($templates) ? $templates : [];
    }

    /** @return object{success:bool,msg?:string,sub_link?:string,vray_links?:string[],remark?:string} */
    private function buildCreateResponse($data, string $remarkHint = '')
    {
        if (!is_object($data)) {
            return (object) ['success' => false, 'msg' => 'Invalid panel response'];
        }
        $username = (string) ($data->username ?? $remarkHint);
        if ($username === '') {
            return (object) ['success' => false, 'msg' => 'Invalid panel response'];
        }

        $subUrl = (string) ($data->subscription_url ?? '');
        if ($subUrl === '') {
            $fresh = $this->getUser($username);
            if (is_object($fresh)) {
                $data = $fresh;
                $subUrl = (string) ($fresh->subscription_url ?? '');
            }
        }

        $panelUrl = (string) ($this->serverConfig['panel_url'] ?? '');
        $subPath = PasarguardConfig::extractSubPath($subUrl);
        $subLink = PasarguardConfig::buildSubscriptionUrl($panelUrl, $subUrl);

        return (object) [
            'success' => true,
            'remark' => $username,
            'sub_link' => $subPath,
            'vray_links' => $subLink !== '' ? [$subLink] : [],
        ];
    }
}
