<?php

/**
 * Покращений клас для роботи з базою даних
 * Інтегрований з модулем Logger для відстеження повільних запитів та помилок
 *
 * @package Flowaxy\Infrastructure\Persistence\Database
 * @version 1.0.0 Alpha prerelease
 */

declare(strict_types=1);

namespace Flowaxy\Infrastructure\Persistence\Database;

// Завантажуємо інтерфейс перед використанням
if (! interface_exists(\Flowaxy\Infrastructure\Persistence\Database\DatabaseInterface::class)) {
    $interfaceFile = __DIR__ . DS . 'DatabaseInterface.php';
    if (file_exists($interfaceFile) && is_readable($interfaceFile)) {
        require_once $interfaceFile;
    }
}

use Flowaxy\Infrastructure\Persistence\Database\DatabaseInterface;
use Flowaxy\Infrastructure\Persistence\Database\ConnectionPool;
use Flowaxy\Infrastructure\Persistence\Database\QueryBuilder;
use Flowaxy\Support\Facades\Hooks;
use Flowaxy\Support\Facades\Log;

// Завантажуємо Settings facade, якщо він ще не завантажений
if (! class_exists(\Flowaxy\Support\Facades\Settings::class)) {
    $settingsFile = __DIR__ . DS . '..' . DS . '..' . DS . '..' . DS . 'Support' . DS . 'Facades' . DS . 'Settings.php';
    if (file_exists($settingsFile) && is_readable($settingsFile)) {
        require_once $settingsFile;
    }
}

use Flowaxy\Support\Facades\Settings;

final class Database implements DatabaseInterface
{
    private static ?self $instance = null;
    private static bool $connectionLogged = false;
    private static bool $isConnecting = false;
    private ?\PDO $connection = null;
    private bool $isConnected = false;
    private ?ConnectionPool $connectionPool = null;
    private bool $useConnectionPool = false;
    private int $connectionAttempts = 0;
    private int $maxConnectionAttempts = 3;
    private int $connectionTimeout = 3;
    private int $hostCheckTimeout = 1;

    private array $queryList = [];
    private array $queryErrors = [];
    private int $queryCount = 0;
    private float $totalQueryTime = 0.0;
    private float $slowQueryThreshold = 1.0;


    private function __construct()
    {
        $this->loadConfigParams();
    }

    private function loadConfigParams(): void
    {
        // TODO: Обновить после миграции SystemConfig
        if (class_exists('SystemConfig')) {
            $systemConfig = \Flowaxy\Infrastructure\Config\SystemConfig::getInstance();
            $this->maxConnectionAttempts = $systemConfig->getDbMaxAttempts();
            $this->connectionTimeout = $systemConfig->getDbConnectionTimeout();
            $this->hostCheckTimeout = $systemConfig->getDbHostCheckTimeout();
            $this->slowQueryThreshold = $systemConfig->getDbSlowQueryThreshold();
        }
    }

    private function getSlowQueryThreshold(): float
    {
        if ($this->slowQueryThreshold === 1.0) {
            // Перевіряємо, чи доступний Settings facade
            if (class_exists(\Flowaxy\Support\Facades\Settings::class)) {
                try {
                    $threshold = \Flowaxy\Support\Facades\Settings::manager()?->get('logger_slow_query_threshold', '1.0') ?? '1.0';
                    $this->slowQueryThreshold = (float)$threshold;
                } catch (\Throwable $e) {
                    // Якщо Settings недоступний, використовуємо значення за замовчуванням
                    $this->slowQueryThreshold = 1.0;
                }
            }
        }
        return $this->slowQueryThreshold;
    }

    public static function getInstance(): self
    {
        if (self::$instance === null) {
            self::$instance = new self();
        }

        return self::$instance;
    }

    public function getConnection(): \PDO
    {
        if ($this->useConnectionPool && $this->connectionPool !== null) {
            return $this->connectionPool->get();
        }

        if (! $this->isConnected || $this->connection === null) {
            $this->connect();
        }

        return $this->connection;
    }

    public function setConnectionPool(ConnectionPool $pool): void
    {
        $this->connectionPool = $pool;
        $this->useConnectionPool = true;
    }

    public function releaseConnection(\PDO $connection): void
    {
        if ($this->useConnectionPool && $this->connectionPool !== null) {
            $this->connectionPool->release($connection);
        }
    }

    private function checkHostAvailability(string $host, int $port = 3306): bool
    {
        if (str_contains($host, ':')) {
            [$host, $port] = explode(':', $host, 2);
            $port = (int)$port;
        }

        try {
            $context = stream_context_create([
                'socket' => [
                    'connect_timeout' => $this->hostCheckTimeout,
                ],
            ]);

            $socket = @stream_socket_client(
                "tcp://{$host}:{$port}",
                $errno,
                $errstr,
                $this->hostCheckTimeout,
                STREAM_CLIENT_CONNECT,
                $context
            );

            if ($socket !== false) {
                fclose($socket);
                return true;
            }

            return false;
        } catch (\Exception $e) {
            return false;
        }
    }

    private function connect(): void
    {
        if ($this->isConnected && $this->connection !== null) {
            return;
        }

        if (self::$isConnecting) {
            return;
        }

        self::$isConnecting = true;

        // Используем константы из database.ini
        $dbHost = defined('DB_HOST') ? DB_HOST : '';
        $dbName = defined('DB_NAME') ? DB_NAME : '';
        $dbUser = defined('DB_USER') ? DB_USER : 'root';
        $dbPass = defined('DB_PASS') ? DB_PASS : '';
        $dbCharset = defined('DB_CHARSET') ? DB_CHARSET : 'utf8mb4';

        if (empty($dbHost) || empty($dbName)) {
            $this->isConnected = false;
            $this->connection = null;
            throw new \Exception('Конфігурація бази даних не встановлена');
        }

        if ($this->connectionAttempts >= $this->maxConnectionAttempts) {
            $error = 'Перевищено максимальну кількість спроб підключення до бази даних';
            $this->logError('Помилка підключення до бази даних', ['error' => $error, 'attempts' => $this->connectionAttempts]);
            throw new \Exception($error);
        }

        $this->connectionAttempts++;
        $timeStart = $this->getRealTime();

        $host = $dbHost;
        $port = 3306;

        if (str_contains($host, ':')) {
            [$host, $port] = explode(':', $host, 2);
            $port = (int)$port;
        }

        if (! $this->checkHostAvailability($host, $port)) {
            $connectionTime = $this->getRealTime() - $timeStart;
            $error = "Сервер бази даних недоступний (хост: {$host}, порт: {$port})";
            $errorContext = [
                'error' => $error,
                'host' => $host,
                'port' => $port,
                'attempt' => $this->connectionAttempts,
                'connection_time' => round($connectionTime, 4),
            ];
            $this->logError('Хост бази даних недоступний', $errorContext);
            throw new \Exception($error);
        }

        try {
            $dsn = sprintf(
                'mysql:host=%s;port=%d;dbname=%s;charset=%s',
                $host,
                $port,
                $dbName,
                $dbCharset
            );

            $options = [
                \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
                \PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC,
                \PDO::ATTR_EMULATE_PREPARES => false,
                \PDO::ATTR_PERSISTENT => false,
                \PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES ' . $dbCharset . ' COLLATE utf8mb4_unicode_ci',
                \PDO::ATTR_TIMEOUT => $this->connectionTimeout,
                \PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true,
                \PDO::ATTR_STRINGIFY_FETCHES => false,
            ];

            $oldTimeout = ini_get('default_socket_timeout');
            ini_set('default_socket_timeout', (string)$this->connectionTimeout);

            try {
                if ($this->useConnectionPool && $this->connectionPool === null) {
                    $this->connectionPool = new ConnectionPool(
                        $dsn,
                        $dbUser,
                        $dbPass,
                        $options,
                        10
                    );
                    $this->connection = $this->connectionPool->get();
                } else {
                    $this->connection = new \PDO($dsn, $dbUser, $dbPass, $options);
                }
            } finally {
                ini_set('default_socket_timeout', $oldTimeout);
            }
            $this->isConnected = true;
            $this->connectionAttempts = 0;

            $connectionTime = $this->getRealTime() - $timeStart;

            // @phpstan-ignore-next-line - это методы PDO, а не системные команды exec()
            $this->connection->exec("SET SESSION sql_mode = 'STRICT_TRANS_TABLES,NO_ZERO_DATE,NO_ZERO_IN_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'");
            // @phpstan-ignore-next-line - это метод PDO, а не системная команда exec()
            $this->connection->exec("SET SESSION time_zone = '+00:00'");
            // @phpstan-ignore-next-line - это метод PDO, а не системная команда exec()
            $this->connection->exec('SET SESSION sql_auto_is_null = 0');

            self::$isConnecting = false;

            if (! self::$connectionLogged) {
                self::$connectionLogged = true;
                $this->logQuery('Підключення до MySQL сервера', [], $connectionTime, false);
            }

        } catch (\PDOException $e) {
            self::$isConnecting = false;
            $this->isConnected = false;
            $this->connection = null;
            $connectionTime = $this->getRealTime() - $timeStart;

            $errorMessage = $e->getMessage();
            $errorCode = $e->getCode();

            $isTimeout = str_contains($errorMessage, 'timeout')
                      || str_contains($errorMessage, 'timed out')
                      || str_contains($errorMessage, 'Connection refused')
                      || $errorCode == 2002
                      || $errorCode == 2003;

            $errorContext = [
                'error' => $errorMessage,
                'code' => $errorCode,
                'attempt' => $this->connectionAttempts,
                'connection_time' => round($connectionTime, 4),
                'host' => $host,
                'port' => $port,
                'database' => $dbName,
            ];

            $this->logError('Помилка підключення до бази даних', $errorContext);

            if ($isTimeout || $this->connectionAttempts >= $this->maxConnectionAttempts) {
                $finalError = $isTimeout
                    ? "Сервер бази даних недоступний (таймаут підключення: {$host}:{$port})"
                    : 'Помилка підключення до бази даних після ' . $this->maxConnectionAttempts . ' спроб: ' . $errorMessage;
                throw new \Exception($finalError);
            }

            // Exponential backoff: затримка збільшується експоненційно з кожною спробою
            // 100ms, 200ms, 400ms, 800ms, etc. (максимум 5 секунд)
            $baseDelay = 100000; // 100ms в мікросекундах
            $exponentialDelay = $baseDelay * (2 ** ($this->connectionAttempts - 1));
            $maxDelay = 5000000; // 5 секунд максимум
            $delay = min($exponentialDelay, $maxDelay);

            try {
                if (class_exists(Log::class)) {
                    Log::debug('Database connection retry with exponential backoff', [
                        'attempt' => $this->connectionAttempts,
                        'delay_ms' => round($delay / 1000, 2),
                    ]);
                } else {
                    @error_log('Database connection retry with exponential backoff: attempt=' . $this->connectionAttempts . ', delay_ms=' . round($delay / 1000, 2));
                }
            } catch (Throwable $e) {
                @error_log('Database connection retry with exponential backoff: attempt=' . $this->connectionAttempts . ', delay_ms=' . round($delay / 1000, 2));
            }

            usleep($delay);
            $this->connect();
        }
    }

    public function query(string $query, array $params = [], bool $logQuery = true): \PDOStatement
    {
        $timeStart = $this->getRealTime();

        try {
            if (! $this->isConnected || $this->connection === null) {
                $this->connect();
            }

            $stmt = $this->connection->prepare($query);
            $stmt->execute($params);

            $executionTime = $this->getRealTime() - $timeStart;
            $this->totalQueryTime += $executionTime;
            $this->queryCount++;

            if ($logQuery) {
                $this->logQuery($query, $params, $executionTime);

                // Логуємо SQL запит
                try {
                    if (class_exists(Log::class)) {
                        Log::debug('SQL Query', ['query' => $query, 'params' => $params, 'execution_time' => $executionTime]);
                    } else {
                        @error_log('SQL Query: ' . $query . ' | execution_time: ' . $executionTime);
                    }
                } catch (Throwable $e) {
                    @error_log('SQL Query: ' . $query . ' | execution_time: ' . $executionTime);
                }

                // Логуємо успішний запит як INFO
                $this->logInfo('SQL запит виконано успішно', [
                    'query' => $this->normalizeQuery($query),
                    'execution_time' => round($executionTime, 4),
                    'query_count' => $this->queryCount,
                ]);

                if ($executionTime >= $this->getSlowQueryThreshold()) {
                    $this->logSlowQuery($query, $params, $executionTime);
                }
            }

            return $stmt;

        } catch (\PDOException $e) {
            $executionTime = $this->getRealTime() - $timeStart;

            $errorContext = [
                'query' => $query,
                'params' => $params,
                'error' => $e->getMessage(),
                'error_code' => $e->getCode(),
                'execution_time' => round($executionTime, 4),
            ];

            if ($this->getSetting('log_db_errors', '1') === '1') {
                Hooks::dispatch('db_error', $errorContext);
            }

            // Логуємо помилку БД
            // Перевіряємо, чи доступний модуль Logger з методом logDbError
            if (\class_exists(\Flowaxy\Modules\Logger\Services\LoggerService::class)) {
                try {
                    $logger = \Flowaxy\Modules\Logger\Services\LoggerService::getInstance();
                    if ($logger && \method_exists($logger, 'logDbError')) {
                        $logger->logDbError('Помилка запиту до бази даних: ' . $e->getMessage(), $errorContext);
                    } else {
                        $this->logError('Помилка запиту до бази даних', $errorContext);
                    }
                } catch (\Exception $loggerException) {
                    // Якщо logger недоступний, використовуємо стандартне логування
                    $this->logError('Помилка запиту до бази даних', $errorContext);
                }
            } else {
                $this->logError('Помилка запиту до бази даних', $errorContext);
            }

            $this->queryErrors[] = $errorContext;

            throw $e;
        }
    }

    public function getRow(string $query, array $params = []): array|false
    {
        $stmt = $this->query($query, $params);
        return $stmt->fetch(\PDO::FETCH_ASSOC);
    }

    public function getAll(string $query, array $params = []): array
    {
        $stmt = $this->query($query, $params);
        return $stmt->fetchAll(\PDO::FETCH_ASSOC);
    }

    public function getValue(string $query, array $params = []): mixed
    {
        $stmt = $this->query($query, $params);
        return $stmt->fetchColumn();
    }

    public function insert(string $query, array $params = []): int|false
    {
        try {
            $stmt = $this->query($query, $params);
            $this->invalidateTableCache($query);
            return (int)$this->connection->lastInsertId();
        } catch (\PDOException $e) {
            return false;
        }
    }

    public function execute(string $query, array $params = []): int
    {
        $stmt = $this->query($query, $params);
        $this->invalidateTableCache($query);
        return $stmt->rowCount();
    }

    public function cachedQuery(string $query, array $params = [], int $ttl = 3600): array
    {
        $cacheKey = 'db_query_' . md5($query . serialize($params));

        try {
            /** @var class-string $cacheClass */
            $cacheClass = \Flowaxy\Infrastructure\Cache\Cache::class;
            // @phpstan-ignore-next-line
            $cache = $cacheClass::getInstance();
            $cached = $cache->get($cacheKey);

            if ($cached !== null) {
                return $cached;
            }
        } catch (\Exception $e) {
            // Cache недоступний, продовжуємо без кешу
        }

        $results = $this->getAll($query, $params);

        try {
            /** @var class-string $cacheClass */
            $cacheClass = \Flowaxy\Infrastructure\Cache\Cache::class;
            // @phpstan-ignore-next-line
            $cache = $cacheClass::getInstance();
            $cache->set($cacheKey, $results, $ttl);
        } catch (\Exception $e) {
            // Cache недоступний, ігноруємо
        }

        return $results;
    }

    private function invalidateCache(string $table): void
    {
        try {
            /** @var class-string $cacheClass */
            $cacheClass = \Flowaxy\Infrastructure\Cache\Cache::class;
            // @phpstan-ignore-next-line
            $cache = $cacheClass::getInstance();
            $cache->delete($table . '_query_cache');
        } catch (\Exception $e) {
            // Cache недоступний, ігноруємо
        }
    }

    private function invalidateTableCache(string $query): void
    {
        if (preg_match('/(?:FROM|INTO|UPDATE|DELETE\s+FROM)\s+`?(\w+)`?/i', $query, $matches)) {
            $table = $matches[1];
            $this->invalidateCache($table);
        }
    }

    public function transaction(callable $callback)
    {
        if ($this->connection === null) {
            throw new \Exception('Немає підключення до бази даних');
        }

        $timeStart = $this->getRealTime();

        try {
            try {
                if (class_exists(Log::class)) {
                    Log::Debug('Початок транзакції');
                } else {
                    @error_log('Початок транзакції');
                }
            } catch (Throwable $e) {
                @error_log('Початок транзакції');
            }
            $this->connection->beginTransaction();
            $result = $callback($this->connection);
            $this->connection->commit();

            $executionTime = $this->getRealTime() - $timeStart;
            $this->logInfo('Транзакцію зафіксовано', ['execution_time' => round($executionTime, 4)]);

            return $result;
        } catch (\Exception $e) {
            if ($this->connection->inTransaction()) {
                $this->connection->rollBack();
            }

            $executionTime = $this->getRealTime() - $timeStart;
            $this->logError('Транзакцію відкочено', [
                'error' => $e->getMessage(),
                'execution_time' => round($executionTime, 4),
            ]);

            throw $e;
        }
    }

    public function escape(string $string): string
    {
        if ($this->connection === null) {
            return addslashes($string);
        }

        return substr($this->connection->quote($string), 1, -1);
    }

    private function logQuery(string $query, array $params, float $executionTime, bool $isUserQuery = true): void
    {
        if (! $isUserQuery && $this->getSetting('log_db_queries', '0') !== '1') {
            return;
        }

        $queryInfo = [
            'query' => $this->normalizeQuery($query),
            'params' => $params,
            'time' => round($executionTime, 4),
            'num' => $this->queryCount,
        ];

        $this->queryList[] = $queryInfo;

        if (count($this->queryList) > 100) {
            array_shift($this->queryList);
        }

        if ($this->getSetting('log_db_queries', '0') === '1') {
            Hooks::dispatch('db_query', $queryInfo);
        }
    }

    private function logSlowQuery(string $query, array $params, float $executionTime): void
    {
        $slowQueryInfo = [
            'query' => $this->normalizeQuery($query),
            'params' => $params,
            'execution_time' => round($executionTime, 4),
            'threshold' => $this->slowQueryThreshold,
            'type' => 'slow_query',
        ];

        if ($this->getSetting('log_slow_queries', '1') === '1') {
            Hooks::dispatch('db_slow_query', $slowQueryInfo);
        }

        // Використовуємо Log::warning() з правильним контекстом
        try {
            if (class_exists(Log::class)) {
                Log::warning('Виявлено повільний запит до бази даних', $slowQueryInfo);
            } else {
                @error_log('Виявлено повільний запит до бази даних: ' . json_encode($slowQueryInfo, JSON_UNESCAPED_UNICODE));
            }
        } catch (Throwable $e) {
            @error_log('Виявлено повільний запит до бази даних: ' . json_encode($slowQueryInfo, JSON_UNESCAPED_UNICODE));
        }
    }

    private function normalizeQuery(string $query): string
    {
        return preg_replace('/\s+/', ' ', trim($query));
    }

    private function getRealTime(): float
    {
        [$seconds, $microSeconds] = explode(' ', microtime());
        return ((float)$seconds + (float)$microSeconds);
    }

    private function getSetting(string $key, string $default = ''): string
    {
        // Перевіряємо, чи доступний Settings facade
        if (! class_exists(\Flowaxy\Support\Facades\Settings::class)) {
            return $default;
        }

        if (class_exists('Flowaxy\Support\Managers\SettingsManager')) {
            $settingKey = 'logger_' . $key;
            try {
                return \Flowaxy\Support\Facades\Settings::manager()?->get($settingKey, (string)$default) ?? $default;
            } catch (\Throwable $e) {
                // Якщо Settings недоступний, повертаємо значення за замовчуванням
                return $default;
            }
        }

        return $default;
    }

    private function logError(string $message, array $context = []): void
    {
        try {
            if (class_exists(Log::class)) {
                Log::error($message, $context);
                return;
            }
        } catch (Throwable $e) {
            // Fallback на error_log если фасад недоступен
        }

        // Fallback: используем error_log если фасад Log недоступен
        $logMessage = $message;
        if (!empty($context)) {
            $logMessage .= ' ' . json_encode($context, JSON_UNESCAPED_UNICODE);
        }
        @error_log($logMessage);
    }

    private function logWarning(string $message, array $context = []): void
    {
        try {
            if (class_exists(Log::class)) {
                Log::warning($message, $context);
                return;
            }
        } catch (Throwable $e) {
            // Fallback на error_log если фасад недоступен
        }

        // Fallback: используем error_log если фасад Log недоступен
        $logMessage = $message;
        if (!empty($context)) {
            $logMessage .= ' ' . json_encode($context, JSON_UNESCAPED_UNICODE);
        }
        @error_log($logMessage);
    }

    private function logInfo(string $message, array $context = []): void
    {
        try {
            if (class_exists(Log::class)) {
                Log::info($message, $context);
                return;
            }
        } catch (Throwable $e) {
            // Fallback на error_log если фасад недоступен
        }

        // Fallback: используем error_log если фасад Log недоступен
        $logMessage = $message;
        if (!empty($context)) {
            $logMessage .= ' ' . json_encode($context, JSON_UNESCAPED_UNICODE);
        }
        @error_log($logMessage);
    }

    private function logDebug(string $message, array $context = []): void
    {
        try {
            if (class_exists(Log::class)) {
                Log::Debug($message, $context);
                return;
            }
        } catch (Throwable $e) {
            // Fallback на error_log если фасад недоступен
        }

        // Fallback: используем error_log если фасад Log недоступен
        $logMessage = $message;
        if (!empty($context)) {
            $logMessage .= ' ' . json_encode($context, JSON_UNESCAPED_UNICODE);
        }
        @error_log($logMessage);
    }


    public function isAvailable(): bool
    {
        if (! defined('DB_HOST') || empty(DB_HOST) || ! defined('DB_NAME') || empty(DB_NAME)) {
            return false;
        }

        try {
            if (! $this->isConnected || $this->connection === null) {
                $this->connect();
            }

            if ($this->connection === null) {
                return false;
            }

            $stmt = $this->connection->query('SELECT 1');
            return $stmt !== false;
        } catch (\Exception $e) {
            $this->isConnected = false;
            $this->connection = null;
            if (defined('DB_HOST') && ! empty(DB_HOST)) {
                $this->logError('Перевірка доступності бази даних не вдалася', ['error' => $e->getMessage()]);
            }
            return false;
        }
    }

    public function databaseExists(): bool
    {
        try {
            // Используем константы из database.ini
            $dbHost = defined('DB_HOST') ? DB_HOST : '';
            $dbName = defined('DB_NAME') ? DB_NAME : '';
            $dbUser = defined('DB_USER') ? DB_USER : 'root';
            $dbPass = defined('DB_PASS') ? DB_PASS : '';
            $dbCharset = defined('DB_CHARSET') ? DB_CHARSET : 'utf8mb4';

            if (empty($dbHost)) {
                return false;
            }

            $host = $dbHost;
            $port = 3306;

            if (str_contains($host, ':')) {
                [$host, $port] = explode(':', $host, 2);
                $port = (int)$port;
            }

            $dsn = sprintf('mysql:host=%s;port=%d;charset=%s', $host, $port, $dbCharset);
            $options = [
                \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
                \PDO::ATTR_TIMEOUT => 2,
            ];

            $tempConnection = new \PDO($dsn, $dbUser, $dbPass, $options);

            $stmt = $tempConnection->prepare('SELECT SCHEMA_NAME FROM information_schema.SCHEMATA WHERE SCHEMA_NAME = ?');
            $stmt->execute([$dbName]);
            $result = $stmt->fetch(\PDO::FETCH_ASSOC);

            return $result !== false;
        } catch (\Exception $e) {
            return false;
        }
    }

    public function ping(): bool
    {
        try {
            if ($this->connection === null) {
                return false;
            }

            $this->connection->query('SELECT 1');
            return true;
        } catch (\PDOException $e) {
            $this->isConnected = false;
            $this->connection = null;
            return false;
        }
    }

    public function disconnect(): void
    {
        $this->connection = null;
        $this->isConnected = false;
        $this->connectionAttempts = 0;
    }

    public function getStats(): array
    {
        $stats = [
            'connected' => $this->isConnected,
            'query_count' => $this->queryCount,
            'total_query_time' => round($this->totalQueryTime, 4),
            'average_query_time' => $this->queryCount > 0 ? round($this->totalQueryTime / $this->queryCount, 4) : 0,
            'slow_queries' => 0,
            'error_count' => count($this->queryErrors),
            'query_list_size' => count($this->queryList),
        ];

        foreach ($this->queryList as $query) {
            if (isset($query['time']) && $query['time'] >= $this->getSlowQueryThreshold()) {
                $stats['slow_queries']++;
            }
        }

        if ($this->connection !== null) {
            try {
                $stmt = $this->connection->query("SHOW STATUS WHERE Variable_name IN ('Threads_connected', 'Threads_running', 'Uptime', 'Questions', 'Slow_queries')");
                while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
                    $key = strtolower($row['Variable_name']);
                    $stats['mysql_' . $key] = (int)($row['Value'] ?? 0);
                }
            } catch (\PDOException $e) {
            }
        }

        return $stats;
    }

    public function getQueryList(): array
    {
        return $this->queryList;
    }

    public function getQueryErrors(): array
    {
        return $this->queryErrors;
    }

    public function setSlowQueryThreshold(float $seconds): void
    {
        $this->slowQueryThreshold = $seconds;

        // Перевіряємо, чи доступний Settings facade перед використанням
        if (class_exists(\Flowaxy\Support\Facades\Settings::class)) {
            try {
                \Flowaxy\Support\Facades\Settings::manager()?->set('logger_slow_query_threshold', (string)$seconds);
            } catch (\Throwable $e) {
                // Якщо Settings недоступний, просто ігноруємо помилку
            }
        }
    }

    public function clearStats(): void
    {
        $this->queryList = [];
        $this->queryErrors = [];
        $this->queryCount = 0;
        $this->totalQueryTime = 0.0;
    }

    public function queryBuilder(): QueryBuilder
    {
        return new QueryBuilder($this);
    }

    private function __clone()
    {
    }

    public function __wakeup(): void
    {
        throw new \Exception('Неможливо десеріалізувати singleton');
    }
}
