<?php

/**
 * Модуль управління налаштуваннями сайту
 * Централізована робота з налаштуваннями через клас
 *
 * @package Flowaxy\Support\Managers
 * @version 1.0.0 Alpha prerelease
 */

declare(strict_types=1);

namespace Flowaxy\Support\Managers;

use Error;
use Exception;
use Flowaxy\Core\Contracts\ContainerInterface;
use Flowaxy\Core\System\Base\BaseModule;
use Flowaxy\Core\System\PathResolver;
use Flowaxy\Support\Facades\Log;
use Flowaxy\Support\Facades\Settings;
use Flowaxy\Support\Helpers\CacheHelper;
use Flowaxy\Support\Helpers\ClassLoaderHelper;
use Throwable;

use function class_exists;
use function is_array;
use function method_exists;

final class SettingsManager extends BaseModule
{
    private array $settings = [];
    private bool $loaded = false;

    /**
     * Ініціалізація модуля
     */
    protected function init(): void
    {
        // Налаштування завантажуються ліниво при першому зверненні
    }

    /**
     * Реєстрація хуків модуля
     */
    public function registerHooks(): void
    {
        // Модуль SettingsManager не реєструє хуки
    }

    /**
     * Отримання інформації про модуль
     *
     * @return array<string, string>
     */
    public function getInfo(): array
    {
        return [
            'name' => 'SettingsManager',
            'title' => 'Менеджер налаштувань',
            'description' => 'Централізоване управління налаштуваннями сайту',
            'version' => '1.0.0 Alpha prerelease',
            'author' => 'Flowaxy CMS',
        ];
    }

    /**
     * Отримання API методів модуля
     *
     * @return array<string, string>
     */
    public function getApiMethods(): array
    {
        return [
            'get' => 'Отримання налаштування',
            'set' => 'Збереження налаштування',
            'delete' => 'Видалення налаштування',
            'all' => 'Отримання всіх налаштувань',
            'has' => 'Перевірка існування налаштування',
        ];
    }

    /**
     * Завантаження всіх налаштувань з БД
     *
     * @param bool $force Примусова перезавантаження
     * @return void
     */
    public function load(bool $force = false): void
    {
        if ($this->loaded && ! $force) {
            return;
        }

        // ВАЖЛИВО: Налаштування сайту зберігаються у файлі storage/config/site.php.
        // Кешувати їх через CacheHelper не можна, бо Cache → SettingsManager створює рекурсію
        // (site_settings -> Cache::get -> SettingsManager::load -> ...), що призводить до дуже повільного завантаження / OOM.
        // Тому завжди читаємо напряму з файлу.
        $this->settings = $this->loadFromDatabase();

        $this->loaded = true;
    }

    /**
     * Завантаження налаштувань з файлу конфігурації
     *
     * @return array<string, string>
     */
    private function loadFromDatabase(): array
    {
        try {
            $configPath = PathResolver::storageConfig() . DS . 'site.php';

            if (!file_exists($configPath)) {
                // Якщо файл не існує, створюємо з дефолтними значеннями
                $this->ensureConfigFile($configPath);
                return $this->loadFromConfigFile($configPath);
            }

            return $this->loadFromConfigFile($configPath);
        } catch (Exception $e) {
            try {
                Log::Error('Помилка завантаження налаштувань з файлу конфігурації', [
                    'exception' => $e,
                ]);
            } catch (Throwable $logError) {
                // Ignore logging errors
            }
            return [];
        }
    }

    /**
     * Завантаження налаштувань з файлу
     *
     * @param string $configPath Шлях до файлу конфігурації
     * @return array<string, string>
     */
    private function loadFromConfigFile(string $configPath): array
    {
        $settings = require $configPath;

        // Конвертуємо всі значення в рядки для сумісності
        $result = [];
        foreach ($settings as $key => $value) {
            $result[$key] = (string)$value;
        }

        return $result;
    }

    /**
     * Створення файлу конфігурації з дефолтними значеннями, якщо він не існує
     *
     * @param string $configPath Шлях до файлу конфігурації
     * @return void
     */
    private function ensureConfigFile(string $configPath): void
    {
        $configDir = dirname($configPath);

        // Створюємо директорію, якщо не існує
        if (!is_dir($configDir)) {
            if (!@mkdir($configDir, 0755, true) && !is_dir($configDir)) {
                // Логируем ошибку создания директории
                try {
                    Log::Error('SettingsManager::ensureConfigFile: Failed to create config directory', [
                        'config_dir' => $configDir,
                        'config_path' => $configPath
                    ]);
                } catch (Throwable $logError) {
                    // Ignore logging errors
                }
                return; // Прерываем, если директорию не удалось создать
            }
        }

        // Створюємо файл з дефолтними налаштуваннями
        if (!file_exists($configPath)) {
            $defaultConfig = <<<'PHP'
<?php

/**
 * Налаштування сайту
 */

return [
    'site_name' => '',
    'site_tagline' => '',
    'site_url' => '',
    'admin_email' => 'admin@example.com',
    'site_protocol' => 'auto',
    'timezone' => '',
    'site_language' => 'uk',
    'date_format' => 'd.m.Y',
    'time_format' => 'H:i:s',
    'week_starts_on' => '1',
    'users_can_register' => '1',
    'default_user_role' => '2',
    'session_lifetime' => '7200',
    'cookie_lifetime' => '86400',
    'cookie_path' => '/',
    'cookie_domain' => '',
    'cookie_httponly' => '1',
    'cookie_secure' => '0',
    'cache_enabled' => '0',
    'cache_default_ttl' => '3600',
    'cache_auto_cleanup' => '1',
    'active_theme' => 'default',
    'components_viewer_settings' => '{"ui\\/buttons":{"enabled":true,"variant":"default","props":[]}}',
];
PHP;
            $written = @file_put_contents($configPath, $defaultConfig);
            if ($written === false) {
                // Логируем ошибку создания файла
                try {
                    Log::Error('SettingsManager::ensureConfigFile: Failed to create config file', [
                        'config_path' => $configPath,
                        'config_dir' => $configDir,
                        'dir_exists' => is_dir($configDir),
                        'dir_writable' => is_writable($configDir)
                    ]);
                } catch (Throwable $logError) {
                    // Ignore logging errors
                }
            } else {
                // Логируем успешное создание файла
                try {
                    Log::Debug('SettingsManager::ensureConfigFile: Config file created successfully', [
                        'config_path' => $configPath,
                        'file_size' => $written
                    ]);
                } catch (Throwable $logError) {
                    // Ignore logging errors
                }
            }
        }
    }

    /**
     * Отримання налаштування
     *
     * @param string $key Ключ налаштування
     * @param string $default Значення за замовчуванням
     * @return string
     */
    public function get(string $key, string $default = ''): string
    {
        $this->load();

        return $this->settings[$key] ?? $default;
    }

    /**
     * Отримання всіх налаштувань
     *
     * @return array<string, string>
     */
    public function all(): array
    {
        $this->load();

        return $this->settings;
    }


    /**
     * Збереження налаштування
     *
     * @param string $key Ключ налаштування
     * @param string $value Значення
     * @return bool
     */
    public function set(string $key, string $value): bool
    {
        try {
            $this->load();

            // Оновлюємо локальний кеш
            $this->settings[$key] = $value;

            // Зберігаємо в файл
            $result = $this->saveToConfigFile();

            if ($result) {
                // Очищаємо кеш
                CacheHelper::forget('site_settings');
            }

            return $result;
        } catch (Exception $e) {
            try {
                Log::Error('Помилка збереження налаштування', [
                    'exception' => $e,
                    'key' => $key,
                ]);
            } catch (Throwable $logError) {
                // Ignore logging errors
            }
            return false;
        }
    }

    /**
     * Збереження кількох налаштувань
     *
     * @param array $settings Масив налаштувань [key => value]
     * @return bool
     */
    public function setMultiple(array $settings): bool
    {
        try {
            $this->load();

            // Оновлюємо локальний кеш
            foreach ($settings as $key => $value) {
                $this->settings[$key] = (string)$value;
            }

            // Зберігаємо в файл
            $result = $this->saveToConfigFile();

            if ($result) {
                // Очищаємо кеш
                CacheHelper::forget('site_settings');
                $this->loaded = true;
            }

            return $result;
        } catch (Exception $e) {
            try {
                Log::Error('Помилка збереження кількох налаштувань', [
                    'exception' => $e,
                ]);
            } catch (Throwable $logError) {
                // Ignore logging errors
            }
            return false;
        }
    }

    /**
     * Видалення налаштування
     *
     * @param string $key Ключ налаштування
     * @return bool
     */
    public function delete(string $key): bool
    {
        try {
            $this->load();

            // Видаляємо з локального кешу
            if (isset($this->settings[$key])) {
                unset($this->settings[$key]);
            }

            // Зберігаємо в файл
            $result = $this->saveToConfigFile();

            if ($result) {
                // Очищаємо кеш
                CacheHelper::forget('site_settings');
            }

            return $result;
        } catch (Exception $e) {
            try {
                Log::Error('Помилка видалення налаштування', [
                    'exception' => $e,
                    'key' => $key,
                ]);
            } catch (Throwable $logError) {
                // Ignore logging errors
            }
            return false;
        }
    }

    /**
     * Збереження налаштувань у файл конфігурації
     *
     * @return bool
     */
    private function saveToConfigFile(): bool
    {
        try {
            $configPath = PathResolver::storageConfig() . DS . 'site.php';
            $this->ensureConfigFile($configPath);

            // Формуємо PHP код для збереження
            $content = "<?php\n\n/**\n * Налаштування сайту\n */\n\nreturn [\n";

            // Ключи настроек логирования, которые не должны сохраняться в site.php
            $loggingKeys = [
                'logging_enabled',
                'logging_levels',
                'logging_types',
                'logging_max_file_size',
                'logging_retention_days',
                'logging_rotation_type',
                'logging_rotation_time',
                'logging_rotation_time_unit',
            ];

            foreach ($this->settings as $key => $value) {
                // Пропускаем настройки логирования - они хранятся в logging.ini
                if (in_array($key, $loggingKeys, true)) {
                    continue;
                }

                $escapedKey = addslashes((string)$key);
                $escapedValue = str_replace(['\\', "'"], ['\\\\', "\\'"], (string)$value);
                $content .= "    '{$escapedKey}' => '{$escapedValue}',\n";
            }

            $content .= "];\n";

            // Атомарне збереження через тимчасовий файл
            $tempFile = $configPath . '.tmp';
            if (file_put_contents($tempFile, $content) !== false) {
                if (rename($tempFile, $configPath)) {
                    return true;
                } else {
                    @unlink($tempFile);
                }
            }

            return false;
        } catch (Exception $e) {
            try {
                Log::Error('Помилка збереження налаштувань у файл', [
                    'exception' => $e,
                ]);
            } catch (Throwable $logError) {
                // Ignore logging errors
            }
            return false;
        }
    }

    /**
     * Перевірка існування налаштування
     *
     * @param string $key Ключ настройки
     * @return bool
     */
    public function has(string $key): bool
    {
        $this->load();

        return isset($this->settings[$key]);
    }

    /**
     * Очищення кешу налаштувань
     *
     * @return void
     */
    public function clearCache(): void
    {
        $this->loaded = false;
        $this->settings = [];

        CacheHelper::forget('site_settings');
    }

    /**
     * Перезавантаження налаштувань
     *
     * @return void
     */
    public function reloadSettings(): void
    {
        $this->load(true);
    }

    // Статичні методи замість глобальних функцій
    public static function getManagerInstance(): ?self
    {
        // Уникаємо рекурсії: перевіряємо, що SettingsManager не ініціалізується
        static $initializing = false;
        if ($initializing) {
            return null;
        }

        if (! class_exists(self::class)) {
            return null;
        }

        try {
            // Получаем через фасад
            $manager = Settings::manager();
            if ($manager !== null) {
                return $manager;
            }

            // Fallback на getInstance()
            $initializing = true;
            $instance = self::getInstance();
            $initializing = false;

            return $instance;
        } catch (Exception $e) {
            $initializing = false;
            try {
                Log::Error('Помилка отримання SettingsManager', [
                    'exception' => $e,
                ]);
            } catch (Throwable $logError) {
                // Ignore logging errors
            }
            return null;
        } catch (Error $e) {
            $initializing = false;
            try {
                Log::Error('Критична помилка отримання SettingsManager', [
                    'exception' => $e,
                ]);
            } catch (Throwable $logError) {
                // Ignore logging errors
            }
            return null;
        }
    }

    public static function getSettingValue(string $key, string $default = ''): string
    {
        $manager = self::getManagerInstance();
        if ($manager !== null) {
            return $manager->get($key, $default);
        }

        return $default;
    }
}

// Глобальні функції для зворотної сумісності з content/ (будуть видалені після оновлення content/)
/**
 * @deprecated Використовуйте SettingsManager::getManagerInstance()
 */
function settingsManager(): ?SettingsManager
{
    return SettingsManager::getManagerInstance();
}

/**
 * @deprecated Використовуйте SettingsManager::getSettingValue()
 */
function getSetting(string $key, string $default = ''): string
{
    return SettingsManager::getSettingValue($key, $default);
}
