<?php

namespace App\Classes\MikrotikService;

use RouterOS\Exceptions\ClientException;
use RouterOS\Exceptions\ConfigException;
use RouterOS\Exceptions\QueryException;
use RouterOS\Exceptions\StreamException;
use RouterOS\Config;
use RouterOS\Client;


class MikrotikConfig
{
    protected Client $client;

    public function __construct(string $host, string $user, string $pass, int $port = 8728)
    {
        try {
            $config = new Config([
                "host" => $host,
                "user" => $user,
                "pass" => $pass,
                "port" => $port,
                // Increase timeouts to better tolerate slow devices/networks
                "socket_timeout" => 60,
                "timeout" => 20,
            ]);

            $this->client = new Client($config);
        } catch (ClientException $exception) {
            $this->ignoreMkOrThrowError("Mikrotik Not Connecting");
        } catch (ConfigException $exception) {
            $this->ignoreMkOrThrowError("Mikrotik Information Not Correct");
        } catch (QueryException $exception) {
            $this->ignoreMkOrThrowError("Unable to process Mikrotik query.");
        }
    }

    private function ignoreMkOrThrowError(string $message = "", int $code = 0)
    {
        if (globalPermission("ignore-mikrotik-check")) {
            return;
        }
        throw new \Exception($message, $code);
    }

    protected function checkIfUserInIgnoreList($username)
    {
        $list = ignoreMKClientList();
        return in_array($username, $list) || globalPermission("ignore-mikrotik-check");
    }

    protected function runQuery($queryObject)
    {
        $attempts = 0;
        $lastException = null;
        while ($attempts < 3) {
            try {
                return $this->client->query($queryObject)->read();
            } catch (StreamException | QueryException | ClientException $e) {
                $lastException = $e;
                // Exponential backoff: 200ms, 500ms, 1000ms
                usleep([200000, 500000, 1000000][$attempts]);
                $attempts++;
            }
        }
        throw $lastException ?? new \Exception('Unknown Mikrotik query failure');
    }

    protected function queryMapper($queryObject, $queryEntries)
    {
        foreach ($queryEntries as $queryKey => $queryValue) {
            $queryObject->equal($queryKey,  $queryValue);
        }
        return $queryObject;
    }
}
