<?php

declare(strict_types=1);

namespace Flowaxy\Infrastructure\Config;

use Flowaxy\Core\System\PathResolver;
use Flowaxy\Support\Facades\Settings;
use Flowaxy\Support\Facades\SettingsFacade;
use Flowaxy\Support\Helpers\ClassLoaderHelper;
use Flowaxy\Support\Managers\SettingsManager;
use Exception;
use Throwable;

use function class_exists;
use const DS;

// Завантажуємо Settings facade, якщо він ще не завантажений
if (! class_exists(Settings::class)) {
    try {
        $flowaxyDir = PathResolver::flowaxy();
        $settingsFile = $flowaxyDir . DS . 'Support' . DS . 'Facades' . DS . 'Settings.php';
        ClassLoaderHelper::loadIfExists($settingsFile);
    } catch (Throwable $e) {
        // Якщо PathResolver недоступний, пропускаємо завантаження
    }
}

// Централізована система конфігурації параметрів системи
// Управління всіма параметрами через SettingsManager
final class SystemConfig
{
    private static ?self $instance = null;
    private array $cache = [];

    // Конструктор (приватний для Singleton)
    private function __construct()
    {
    }

    // Отримання екземпляра класу (Singleton)
    public static function getInstance(): self
    {
        if (self::$instance === null) {
            self::$instance = new self();
        }

        return self::$instance;
    }

    // Отримання параметра з кешуванням (публічний метод для зручності)
    public function get(string $key, mixed $default = null): mixed
    {
        return $this->getParam($key, $default);
    }

    // Отримання параметра з кешуванням
    private function getParam(string $key, mixed $default = null): mixed
    {
        if (isset($this->cache[$key])) {
            return $this->cache[$key];
        }

        if (class_exists(SettingsManager::class)) {
            // Використовуємо правильний клас Settings замість SettingsFacade
            if (class_exists(Settings::class)) {
                $settings = Settings::manager();
            } elseif (class_exists(SettingsFacade::class)) {
                // Fallback для зворотної сумісності
                $settings = SettingsFacade::manager();
            } else {
                $settings = null;
            }
            if ($settings !== null) {
                $value = $settings->get($key, (string)$default);
                // Перетворюємо рядок на потрібний тип
                $this->cache[$key] = $this->convertValue($value, $default);

                return $this->cache[$key];
            }
        }

        $this->cache[$key] = $default;

        return $default;
    }

    // Перетворення значення на потрібний тип
    private function convertValue(mixed $value, mixed $default): mixed
    {
        if ($value === '' || $value === null) {
            return $default;
        }

        // Визначаємо тип за замовчуванням
        if (is_int($default)) {
            return (int)$value;
        } elseif (is_float($default)) {
            return (float)$value;
        } elseif (is_bool($default)) {
            return in_array(strtolower((string)$value), ['1', 'true', 'yes', 'on'], true);
        }

        return $value;
    }

    // Очищення кешу
    public function clearCache(): void
    {
        $this->cache = [];
    }

    // ========== Параметри сесій ==========

    // Час життя сесії (в секундах)
    public function getSessionLifetime(): int
    {
        return $this->getParam('session_lifetime', 7200); // 2 години за замовчуванням
    }

    // Ім'я сесії
    public function getSessionName(): string
    {
        return $this->getParam('session_name', 'PHPSESSID');
    }

    // ========== Параметри бази даних ==========

    // Таймаут підключення до БД (в секундах)
    public function getDbConnectionTimeout(): int
    {
        return $this->getParam('db_connection_timeout', 3);
    }

    // Максимальна кількість спроб підключення до БД
    public function getDbMaxAttempts(): int
    {
        return $this->getParam('db_max_attempts', 3);
    }

    // Таймаут перевірки хоста БД (в секундах)
    public function getDbHostCheckTimeout(): int
    {
        return $this->getParam('db_host_check_timeout', 1);
    }

    // Поріг повільних запитів (в секундах)
    public function getDbSlowQueryThreshold(): float
    {
        return (float)$this->getParam('db_slow_query_threshold', 1.0);
    }

    // ========== Параметри кешу ==========

    // Увімкнено кеш
    public function isCacheEnabled(): bool
    {
        return $this->getParam('cache_enabled', true);
    }

    // Час життя кешу за замовчуванням (в секундах)
    public function getCacheDefaultTtl(): int
    {
        return $this->getParam('cache_default_ttl', 3600); // 1 година
    }

    // Автоматичне очищення кешу
    public function isCacheAutoCleanup(): bool
    {
        return $this->getParam('cache_auto_cleanup', true);
    }

    // ========== Параметри логування ==========

    // Увімкнено логування
    public function isLoggingEnabled(): bool
    {
        return $this->getParam('logging_enabled', true);
    }

    // Мінімальний рівень логування
    public function getLoggingLevel(): string
    {
        return $this->getParam('logging_level', 'INFO');
    }

    // Максимальний розмір файлу логу (в байтах)
    public function getLoggingMaxFileSize(): int
    {
        return $this->getParam('logging_max_file_size', 10485760); // 10 MB
    }

    // Кількість днів зберігання логів
    public function getLoggingRetentionDays(): int
    {
        return $this->getParam('logging_retention_days', 30);
    }

    // ========== Параметри завантаження файлів ==========

    // Максимальний розмір завантажуваного файлу (в байтах)
    public function getUploadMaxFileSize(): int
    {
        return $this->getParam('upload_max_file_size', 10485760); // 10 MB
    }

    // Дозволені розширення файлів
    public function getUploadAllowedExtensions(): array
    {
        $extensions = $this->getParam('upload_allowed_extensions', 'jpg,jpeg,png,gif,pdf,doc,docx,zip');
        if (is_string($extensions)) {
            return array_map('trim', explode(',', $extensions));
        }

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

    // Дозволені MIME типи
    public function getUploadAllowedMimeTypes(): array
    {
        $mimeTypes = $this->getParam('upload_allowed_mime_types', 'image/jpeg,image/png,image/gif,application/pdf');
        if (is_string($mimeTypes)) {
            return array_map('trim', explode(',', $mimeTypes));
        }

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

    // ========== Параметри безпеки ==========

    // Мінімальна довжина пароля
    public function getPasswordMinLength(): int
    {
        return $this->getParam('password_min_length', 8);
    }

    // Час життя CSRF токена (в секундах)
    public function getCsrfTokenLifetime(): int
    {
        return $this->getParam('csrf_token_lifetime', 3600); // 1 година
    }

    // ========== Параметри продуктивності ==========

    // Увімкнено оптимізацію запитів
    public function isQueryOptimizationEnabled(): bool
    {
        return $this->getParam('query_optimization_enabled', true);
    }

    // Максимальна кількість запитів в секунду
    public function getMaxQueriesPerSecond(): int
    {
        return $this->getParam('max_queries_per_second', 100);
    }

    // Запобігання клонуванню та десеріалізації
    private function __clone()
    {
    }

    // Запобігання десеріалізації
    public function __wakeup(): void
    {
        throw new Exception('Cannot unserialize singleton');
    }

    // Статичний метод замість глобальної функції
    public static function instance(): self
    {
        return self::getInstance();
    }
}
