<?php

/**
 * Менеджер плагінів системи
 *
 * @package Flowaxy\Support\Managers
 * @version 1.0.0 Alpha prerelease
 */

declare(strict_types=1);

namespace Flowaxy\Support\Managers;

use Exception;
use Flowaxy\Core\Contracts\HookManagerInterface;
use Flowaxy\Core\Hooks\HookManager;
use Flowaxy\Core\Hooks\HookType;
use Flowaxy\Core\System\Base\BaseModule;
use Flowaxy\Core\System\ModuleLoader;
use Flowaxy\Core\System\PathResolver;
use Flowaxy\Contracts\Security\PluginCapabilityInterface;
use Flowaxy\Domain\Plugin\Services\ActivatePluginService;
use Flowaxy\Domain\Plugin\Services\ApplicationPluginLifecycleService;
use Flowaxy\Domain\Plugin\Services\DeactivatePluginService;
use Flowaxy\Domain\Plugin\Services\InstallPluginService;
use Flowaxy\Domain\Plugin\Services\PluginCapabilityManager;
use Flowaxy\Domain\Plugin\Services\PluginLifecycleInterface;
use Flowaxy\Domain\Plugin\Services\UninstallPluginService;
use Flowaxy\Infrastructure\Cache\PluginCacheManager;
use Flowaxy\Infrastructure\Config\PluginConfigManager;
use Flowaxy\Infrastructure\Filesystem\File;
use Flowaxy\Infrastructure\Filesystem\PluginFilesystem;
use Flowaxy\Infrastructure\Persistence\Repositories\PluginRepository;
use Flowaxy\Support\Base\BasePlugin;
use Flowaxy\Support\Facades\Hooks;
use Flowaxy\Support\Facades\Log;
use Flowaxy\Support\Helpers\CacheHelper;
use Flowaxy\Support\Helpers\ClassLoaderHelper;
use Flowaxy\Support\Helpers\DatabaseHelper;
use Flowaxy\Support\Helpers\FileHelper;
use Flowaxy\Support\Helpers\JsonHelper;
use Flowaxy\Support\Helpers\ResourceCleanupHelper;
use Flowaxy\Support\Managers\PluginLoader;
use PDO;
// Используем глобальный \RuntimeException напрямую (без use), чтобы избежать конфликтов static analysis
use Throwable;

use function function_exists;
use function interface_exists;
use const DS;

final class PluginManager extends BaseModule
{
    /**
     * @var array<string, BasePlugin>
     */
    private array $plugins = [];

    /**
     * @var array<string, array<int, mixed>>
     */
    private array $hooks = [];
    private HookManagerInterface $hookManager;
    private string $pluginsDir = '';
    private ?PluginLifecycleInterface $lifecycle = null;
    private ?PluginCapabilityManager $capabilityManager = null;
    private ?string $lastInstallError = null;

    protected function init(): void
    {
        $this->pluginsDir = PathResolver::plugins() . DS;

        // Завантажуємо необхідні інтерфейси та класи перед використанням
        $flowaxyDir = PathResolver::flowaxy();

        // Убеждаемся, что ClassLoaderHelper загружен
        if (!class_exists(ClassLoaderHelper::class, false)) {
            $classLoaderHelperFile = $flowaxyDir . DS . 'Support' . DS . 'Helpers' . DS . 'ClassLoaderHelper.php';
            if (file_exists($classLoaderHelperFile)) {
                require_once $classLoaderHelperFile;
            }
        }

        // Завантажуємо HookRegistryInterface ПЕРЕД HookManagerInterface (HookManagerInterface extends HookRegistryInterface)
        if (!interface_exists('Flowaxy\Core\Contracts\HookRegistryInterface')) {
            $hookRegistryInterfaceFile = $flowaxyDir . DS . 'Core' . DS . 'Contracts' . DS . 'HookRegistryInterface.php';
            ClassLoaderHelper::loadIfExists($hookRegistryInterfaceFile);
        }

        // Завантажуємо HookManagerInterface перед HookManager
        if (!interface_exists('Flowaxy\Core\Contracts\HookManagerInterface')) {
            $hookManagerInterfaceFile = $flowaxyDir . DS . 'Core' . DS . 'Contracts' . DS . 'HookManagerInterface.php';
            ClassLoaderHelper::loadIfExists($hookManagerInterfaceFile);
        }

        // Завантажуємо залежності HookManager перед його створенням
        // HookRegistry та HookPerformanceMonitor потрібні для HookManager
        if (!class_exists('Flowaxy\Core\Hooks\HookRegistry')) {
            $hookRegistryFile = $flowaxyDir . DS . 'Core' . DS . 'Hooks' . DS . 'HookRegistry.php';
            ClassLoaderHelper::loadIfExists($hookRegistryFile);
        }

        if (!class_exists('Flowaxy\Core\Hooks\HookPerformanceMonitor')) {
            $hookPerformanceMonitorFile = $flowaxyDir . DS . 'Core' . DS . 'Hooks' . DS . 'HookPerformanceMonitor.php';
            ClassLoaderHelper::loadIfExists($hookPerformanceMonitorFile);
        }

        // Отримуємо HookManager через функцію hooks() (визначена в кінці цього файлу)
        // Використовуємо повне ім'я функції для доступу з простору імен
        if (function_exists('hooks')) {
            $this->hookManager = hooks();
        } else {
            // Fallback: створюємо HookManager напрямую
            $hookManagerFile = $flowaxyDir . DS . 'Core' . DS . 'Hooks' . DS . 'HookManager.php';
            if (!class_exists(HookManager::class)) {
                ClassLoaderHelper::loadIfExists($hookManagerFile);
            }
            if (class_exists(HookManager::class)) {
                $this->hookManager = new HookManager();
            } else {
                // Критична ситуація, але кидаємо звичайний Exception, щоб уникнути проблем static analysis
                throw new Exception('HookManager not available');
            }
        }
    }

    public function registerHooks(): void {}

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

    /**
     * Отримання API методів модуля
     *
     * @return array<string, string>
     */
    public function getApiMethods(): array
    {
        return [
            'getAllPlugins' => 'Отримання всіх плагінів',
            'getActivePlugins' => 'Отримання активних плагінів',
            'getPlugin' => 'Отримання плагіна за slug',
            'installPlugin' => 'Встановлення плагіна',
            'activatePlugin' => 'Активація плагіна',
            'deactivatePlugin' => 'Деактивація плагіна',
            'uninstallPlugin' => 'Видалення плагіна',
            'addHook' => 'Додавання хука',
            'prepareHook' => 'Підготовка даних перед викликом хука',
            'hasHook' => 'Перевірка існування хука',
            'autoDiscoverPlugins' => 'Автоматичне виявлення плагінів',
        ];
    }

    public function initializePlugins(): void
    {
        static $initialized = false;

        if ($initialized) {
            return;
        }

        $this->loadPlugins('handle_early_request');

        foreach ($this->plugins as $slug => $plugin) {
            static $initializedPlugins = [];
            if (isset($initializedPlugins[$slug])) {
                continue;
            }

            // Plugin завжди має метод init, але перевіряємо для безпеки
            try {
                if ($plugin instanceof BasePlugin) {
                    $plugin->init();
                    $initializedPlugins[$slug] = true;
                }
            } catch (Exception $e) {
                try {
                    Log::Error("Помилка ініціалізації плагіна", ['exception' => $e, 'slug' => $slug]);
                } catch (Throwable $logError) {
                    // Ignore logging errors
                }
            }
        }

        $initialized = true;
    }

    private function loadPlugins(?string $forHook = null): void
    {
        static $pluginsLoaded = false;
        static $hooksChecked = [];

        if ($pluginsLoaded) {
            return;
        }

        if ($forHook && ! in_array($forHook, ['admin_menu', 'admin_register_routes', 'handle_early_request', 'public_routes'])) {
            return;
        }

        if ($forHook && isset($hooksChecked[$forHook])) {
            return;
        }

        // Загружаем PluginConfigManager перед использованием (не требует БД)
        if (!class_exists(PluginConfigManager::class, false)) {
            ClassLoaderHelper::ensureLoaded(PluginConfigManager::class);
        }

        // Загружаем PluginMetadataHelper перед использованием (не требует БД)
        if (!class_exists(\Flowaxy\Support\Helpers\PluginMetadataHelper::class, false)) {
            ClassLoaderHelper::ensureLoaded(\Flowaxy\Support\Helpers\PluginMetadataHelper::class);
        }

        // Проверяем доступность БД без вызова getDB() (чтобы избежать ошибок)
        $hasDatabase = defined('DB_HOST') && !empty(DB_HOST) && defined('DB_NAME') && !empty(DB_NAME);

        try {
            // Получаем список активных плагинов из конфига (НЕ из БД)
            $allPlugins = PluginConfigManager::getAll();
            $activePlugins = [];
            foreach ($allPlugins as $slug => $status) {
                if ($status === 'active') {
                    $activePlugins[] = $slug;
                }
            }

            // Если БД доступна, можем кешировать список активных slug,
            // но наличие кеша НЕ должно быть обязательным для загрузки плагинов.
            if ($hasDatabase) {
                $db = $this->getDB();
                if ($db) {
                    // Загружаем CacheHelper перед использованием
                    if (!class_exists(CacheHelper::class, false)) {
                        ClassLoaderHelper::ensureLoaded(CacheHelper::class);
                    }

                    $cacheKey = 'active_plugins_list';
                    $activePlugins = CacheHelper::remember($cacheKey, function () use ($activePlugins) {
                        return $activePlugins;
                    }, 300);
                }
            }

            // Загружаем каждый активный плагин:
            foreach ($activePlugins as $slug) {
                if (isset($this->plugins[$slug])) {
                    continue;
                }

                $loaded = false;

                if ($hasDatabase) {
                    $this->loadPluginFull($slug);
                    if (isset($this->plugins[$slug])) {
                        $loaded = true;
                    }
                }

                if (! $loaded) {
                    // Файловый фоллбек: создаём минимальный pluginData только со slug
                    $this->loadPlugin(['slug' => $slug]);
                }
            }

            $pluginsLoaded = true;
            if ($forHook) {
                $hooksChecked[$forHook] = true;
            }
        } catch (Exception $e) {
            try {
                Log::Error('Помилка завантаження плагінів', ['exception' => $e]);
            } catch (Throwable $logError) {
                // Ignore logging errors
            }
        }
    }

    private function loadPluginFull(string $slug): void
    {
        if (isset($this->plugins[$slug])) {
            return;
        }

        // Загружаем PluginConfigManager перед использованием
        if (!class_exists(PluginConfigManager::class, false)) {
            ClassLoaderHelper::ensureLoaded(PluginConfigManager::class);
        }

        // Проверяем, что плагин установлен и активен через PluginConfigManager
        if (!PluginConfigManager::isInstalled($slug) || !PluginConfigManager::isActive($slug)) {
            return;
        }

        // Загружаем PluginMetadataHelper перед использованием
        if (!class_exists(\Flowaxy\Support\Helpers\PluginMetadataHelper::class, false)) {
            ClassLoaderHelper::ensureLoaded(\Flowaxy\Support\Helpers\PluginMetadataHelper::class);
        }

        // Загружаем CacheHelper перед использованием
        if (!class_exists(CacheHelper::class, false)) {
            ClassLoaderHelper::ensureLoaded(CacheHelper::class);
        }

        try {
            $cacheKey = 'plugin_data_' . $slug;

            $pluginData = CacheHelper::remember($cacheKey, function () use ($slug) {
                // Получаем метаданные плагина из файловой системы
                $metadata = \Flowaxy\Support\Helpers\PluginMetadataHelper::readMetadata($slug);

                if (empty($metadata)) {
                    return null;
                }

                // Формируем данные плагина в формате, совместимом с loadPlugin()
                return [
                    'slug' => $slug,
                    'name' => $metadata['name'] ?? ucfirst($slug),
                    'version' => $metadata['version'] ?? '1.0.0',
                    'description' => $metadata['description'] ?? '',
                    'author' => $metadata['author'] ?? '',
                    'is_active' => 1,
                ];
            }, 300);

            if ($pluginData) {
                $this->loadPlugin($pluginData);
            }
        } catch (Exception $e) {
            try {
                Log::Error("Помилка завантаження даних плагіна", ['exception' => $e, 'slug' => $slug]);
            } catch (Throwable $logError) {
                // Ignore logging errors
            }
        }
    }

    /**
     * Отримання імені класу плагіна з slug
     */
    private function getPluginClassName(string $pluginSlug): string
    {
        $parts = explode('-', $pluginSlug);
        $className = '';
        foreach ($parts as $part) {
            $className .= ucfirst($part);
        }

        return $className . 'Plugin';
    }

    private function loadPlugin(array $pluginData): void
    {
        $slug = $pluginData['slug'] ?? '';
        if (empty($slug) || isset($this->plugins[$slug])) {
            return;
        }

        // Використовуємо оптимізований PluginLoader, якщо доступний
        if (class_exists(PluginLoader::class)) {
            try {
                // Ініціалізуємо PluginLoader, якщо ще не ініціалізований
                PluginLoader::initialize($this->pluginsDir);

                $plugin = PluginLoader::load($slug, $pluginData);
                if ($plugin !== null) {
                    $this->plugins[$slug] = $plugin;
                    return;
                }
            } catch (Exception $e) {
                // Fallback до старої реалізації
                try {
                    Log::Error("Помилка завантаження плагіна через PluginLoader", ['exception' => $e, 'slug' => $slug]);
                } catch (Throwable $logError) {
                    // Ignore logging errors
                }
            }
        }

        // Fallback: стара реалізація для зворотної сумісності
        $pluginPath = $this->getPluginPath($slug);

        // Используем ClassLoaderHelper для безопасной загрузки
        if (!ClassLoaderHelper::loadIfExists($pluginPath)) {
            return;
        }

        try {
            $className = $this->getPluginClassName($slug);
            if (class_exists($className)) {
                /**
                 * @var BasePlugin $plugin
                 */
                $plugin = new $className();
                $this->plugins[$slug] = $plugin;
            }
        } catch (Exception $e) {
            try {
                Log::Error("Помилка завантаження плагіна", ['exception' => $e]);
            } catch (Throwable $logError) {
                // Ignore logging errors
            }
        }
    }

    /**
     * Отримання шляху до файлу плагіна (НОВА структура)
     *
     * Точка входу тільки одна: `Plugin.php` в корені папки плагіна.
     */
    private function getPluginPath(string $pluginSlug): string
    {
        return $this->pluginsDir . $pluginSlug . DS . 'Plugin.php';
    }

    /**
     * @return BasePlugin|object|null
     */
    private function getPluginInstance(string $pluginSlug)
    {
        if (isset($this->plugins[$pluginSlug])) {
            return $this->plugins[$pluginSlug];
        }

        // Загружаем PluginConfigManager перед использованием
        if (!class_exists(PluginConfigManager::class, false)) {
            ClassLoaderHelper::ensureLoaded(PluginConfigManager::class);
        }

        // Загружаем PluginMetadataHelper перед использованием
        if (!class_exists(\Flowaxy\Support\Helpers\PluginMetadataHelper::class, false)) {
            ClassLoaderHelper::ensureLoaded(\Flowaxy\Support\Helpers\PluginMetadataHelper::class);
        }

        // Проверяем, что плагин установлен через PluginConfigManager
        if (!PluginConfigManager::isInstalled($pluginSlug)) {
            return null;
        }

        // Загружаем CacheHelper перед использованием
        if (!class_exists(CacheHelper::class, false)) {
            ClassLoaderHelper::ensureLoaded(CacheHelper::class);
        }

        try {
            // Получаем метаданные плагина из файловой системы
            $metadata = \Flowaxy\Support\Helpers\PluginMetadataHelper::readMetadata($pluginSlug);

            if (empty($metadata)) {
                return null;
            }

            // Формируем данные плагина в формате, совместимом с loadPlugin()
            $pluginData = [
                'slug' => $pluginSlug,
                'name' => $metadata['name'] ?? ucfirst($pluginSlug),
                'version' => $metadata['version'] ?? '1.0.0',
                'description' => $metadata['description'] ?? '',
                'author' => $metadata['author'] ?? '',
                'is_active' => PluginConfigManager::isActive($pluginSlug) ? 1 : 0,
            ];

            CacheHelper::forget('plugin_data_' . $pluginSlug);
            $this->loadPlugin($pluginData);

            return $this->plugins[$pluginSlug] ?? null;
        } catch (Exception $e) {
            try {
                Log::Error("Помилка завантаження екземпляра плагіна", ['exception' => $e, 'plugin_slug' => $pluginSlug]);
            } catch (Throwable $logError) {
                // Ignore logging errors
            }
        }

        return null;
    }

    public function addHook(string $hookName, callable $callback, int $priority = 10): void
    {
        $this->hookManager->filter($hookName, $callback, $priority);

        if (! isset($this->hooks[$hookName])) {
            $this->hooks[$hookName] = [];
        }
        $this->hooks[$hookName][] = [
            'callback' => $callback,
            'priority' => $priority,
        ];
        usort($this->hooks[$hookName], fn($a, $b) => $a['priority'] - $b['priority']);
    }

    public function prepareHook(string $hookName, HookType $type, mixed $payload = null): mixed
    {
        if (empty($hookName)) {
            return $payload;
        }

        if (($hookName === 'admin_menu' || $hookName === 'admin_register_routes') && class_exists('ModuleLoader')) {
            static $adminModulesChecked = false;
            if (! $adminModulesChecked) {
                $this->loadAdminModules(false);
                $adminModulesChecked = true;
            }
        }

        if (! $this->hookManager->has($hookName) && ! isset($this->hooks[$hookName])) {
            if ($hookName === 'admin_menu' || $hookName === 'admin_register_routes' || $hookName === 'handle_early_request' || $hookName === 'public_routes') {
                // Пытаемся загрузить плагины, но не критично, если БД не настроена
                try {
                    $this->loadPlugins($hookName);
                    $this->initializePlugins();
                } catch (Throwable $e) {
                    // Игнорируем ошибки загрузки плагинов - базовое меню должно работать без них
                }
            } else {
                return $payload;
            }
        }

        if (! isset($this->hooks[$hookName])) {
            return $payload;
        }

        foreach ($this->hooks[$hookName] as $hook) {
            if (! is_callable($hook['callback'])) {
                continue;
            }

            try {
                if ($type === HookType::Action) {
                    $args = is_array($payload) ? $payload : [$payload];
                    call_user_func_array($hook['callback'], $args);
                } else {
                    $result = call_user_func($hook['callback'], $payload);
                    if ($result !== null) {
                        $payload = $result;
                    }
                }
            } catch (Exception $e) {
                try {
                    Log::Error("Помилка виконання хука", ['exception' => $e, 'hook' => $hookName]);
                } catch (Throwable $logError) {
                    // Ignore logging errors
                }
            }
        }

        return $payload;
    }

    private function loadAdminModules(bool $forceLoadAll = false): void
    {
        static $adminModulesLoaded = false;
        static $allModulesLoaded = false;

        if ($forceLoadAll) {
            if ($allModulesLoaded) {
                $this->ensureModulesHooksRegistered();

                return;
            }
        } else {
            if ($adminModulesLoaded) {
                return;
            }

            $loadedModules = ModuleLoader::getLoadedModules();
            if (count($loadedModules) > 1) {
                $adminModulesLoaded = true;

                return;
            }
        }

        static $modulesList = null;

        if ($modulesList === null) {
            $managersDir = PathResolver::engine() . DS . 'Support' . DS . 'Managers';
            $modules = glob($managersDir . DS . '*.php');
            $modulesList = [];

            if ($modules !== false) {
                foreach ($modules as $moduleFile) {
                    $moduleName = basename($moduleFile, '.php');

                    if (
                        $moduleName === 'loader' ||
                        $moduleName === 'compatibility' ||
                        $moduleName === 'PluginManager'
                    ) {
                        continue;
                    }

                    $modulesList[] = $moduleName;
                }
            }
        }

        foreach ($modulesList as $moduleName) {
            if (! ModuleLoader::isModuleLoaded($moduleName)) {
                ModuleLoader::loadModule($moduleName);
            }
        }

        $this->ensureModulesHooksRegistered();

        if ($forceLoadAll) {
            $allModulesLoaded = true;
        } else {
            $adminModulesLoaded = true;
        }
    }

    private function ensureModulesHooksRegistered(): void
    {
        if (! class_exists('ModuleLoader')) {
            return;
        }

        $loadedModules = ModuleLoader::getLoadedModules();
        foreach ($loadedModules as $moduleName => $module) {
            if (is_object($module) && method_exists($module, 'registerHooks')) {
                $needsRegistration = false;

                if (! isset($this->hooks['admin_menu']) || ! $this->hasModuleHook($moduleName, 'admin_menu')) {
                    $needsRegistration = true;
                }

                if (! isset($this->hooks['admin_register_routes']) || ! $this->hasModuleHook($moduleName, 'admin_register_routes')) {
                    $needsRegistration = true;
                }

                if ($needsRegistration) {
                    try {
                        $module->registerHooks();
                    } catch (Exception $e) {
                        try {
                            Log::Error("Помилка реєстрації хуків модуля", ['exception' => $e, 'module' => $moduleName]);
                        } catch (Throwable $logError) {
                            // Ignore logging errors
                        }
                    }
                }
            }
        }
    }

    private function hasModuleHook(string $moduleName, string $hookName): bool
    {
        if (! isset($this->hooks[$hookName])) {
            return false;
        }

        foreach ($this->hooks[$hookName] as $hook) {
            if (
                is_array($hook['callback']) &&
                isset($hook['callback'][0]) &&
                is_object($hook['callback'][0])
            ) {
                $objectClass = get_class($hook['callback'][0]);
                if ($objectClass === $moduleName || str_contains($objectClass, $moduleName)) {
                    return true;
                }
            }
        }

        return false;
    }

    public function hasHook(string $hookName): bool
    {
        return $this->hookManager->has($hookName) ||
            (! empty($hookName) && isset($this->hooks[$hookName]) && ! empty($this->hooks[$hookName]));
    }

    public function getHookManager(): HookManagerInterface
    {
        return $this->hookManager;
    }

    public function getAllPlugins(): array
    {
        // Загружаем CacheHelper перед использованием
        if (!class_exists(CacheHelper::class, false)) {
            ClassLoaderHelper::ensureLoaded(CacheHelper::class);
        }

        // Загружаем PluginMetadataHelper перед использованием
        if (!class_exists(\Flowaxy\Support\Helpers\PluginMetadataHelper::class, false)) {
            ClassLoaderHelper::ensureLoaded(\Flowaxy\Support\Helpers\PluginMetadataHelper::class);
        }

        // Кешуємо результат сканувания файлової системи
        $cacheKey = 'all_plugins_filesystem';

        // Очищаем кеш для отладки (временно, чтобы видеть изменения сразу)
        CacheHelper::forget($cacheKey);

        return CacheHelper::remember($cacheKey, function (): array {
            $allPlugins = [];

            if (! is_dir($this->pluginsDir)) {
                return $allPlugins;
            }

            $directories = glob($this->pluginsDir . '*', GLOB_ONLYDIR);

            foreach ($directories as $dir) {
                $pluginSlug = basename($dir);
                $pluginFile = $dir . DS . 'Plugin.php';

                @error_log("PluginManager: Checking plugin directory - slug: {$pluginSlug}, file: {$pluginFile}, exists: " . (file_exists($pluginFile) ? 'yes' : 'no'));

                if (file_exists($pluginFile)) {
                    try {
                        $config = \Flowaxy\Support\Helpers\PluginMetadataHelper::readMetadata($pluginSlug);

                        if (is_array($config) && ! empty($config)) {
                            if (empty($config['slug'])) {
                                $config['slug'] = $pluginSlug;
                            }

                            // Проверяем существование Plugin.php напрямую (без использования класса File)
                            $config['has_plugin_file'] = file_exists($pluginFile);

                            // Получаем статус из конфигурации (если плагин еще не добавлен, будет 'Non-install')
                            if (!class_exists(\Flowaxy\Infrastructure\Config\PluginConfigManager::class, false)) {
                                ClassLoaderHelper::ensureLoaded(\Flowaxy\Infrastructure\Config\PluginConfigManager::class);
                            }
                            $status = \Flowaxy\Infrastructure\Config\PluginConfigManager::getStatus($pluginSlug);
                            $config['status'] = $status;

                            $allPlugins[$pluginSlug] = $config;

                            @error_log("PluginManager: Plugin discovered - slug: {$pluginSlug}, name: " . ($config['name'] ?? 'N/A') . ", status: {$status}");
                        } else {
                            @error_log("PluginManager: Failed to read metadata - slug: {$pluginSlug}, config empty or invalid");
                        }
                    } catch (Exception $e) {
                        @error_log("PluginManager: Exception reading Plugin.php - slug: {$pluginSlug}, error: " . $e->getMessage());
                    }
                }
            }

            @error_log("PluginManager: getAllPlugins result - count: " . count($allPlugins) . ", plugins: " . implode(', ', array_keys($allPlugins)));

            return $allPlugins;
        }, 300); // Кешуємо на 5 хвилин
    }

    public function autoDiscoverPlugins(): int
    {
        // Загружаем CacheHelper перед использованием
        if (!class_exists(CacheHelper::class, false)) {
            ClassLoaderHelper::ensureLoaded(CacheHelper::class);
        }

        // Кешуємо результат пошуку плагінів
        $cacheKey = 'discovered_plugins_list';

        $allPlugins = CacheHelper::remember($cacheKey, function () {
            return $this->getAllPlugins();
        }, 600); // Кешуємо на 10 хвилин

        $installedCount = 0;

        // Загружаем PluginConfigManager перед использованием
        if (!class_exists(PluginConfigManager::class, false)) {
            ClassLoaderHelper::ensureLoaded(PluginConfigManager::class);
        }

        // Оптимізація: використовуємо пакетну перевірку
        $slugs = array_keys($allPlugins);
        if (empty($slugs)) {
            return 0;
        }

        // Отримуємо всі встановлені плагіни з конфигурации
        $allInstalled = PluginConfigManager::loadConfig();
        $installedSlugs = array_keys($allInstalled);

        // Встановлюємо тільки нові плагіни
        foreach ($allPlugins as $slug => $config) {
            if (!in_array($slug, $installedSlugs, true)) {
                try {
                    if ($this->installPlugin($slug)) {
                        $installedCount++;
                    }
                } catch (Exception $e) {
                    try {
                        Log::Error("Помилка встановлення плагіна", ['exception' => $e, 'slug' => $slug]);
                    } catch (Throwable $logError) {
                        // Ignore logging errors
                    }
                }
            }
        }

        // Очищаємо кеш після встановлення
        if ($installedCount > 0) {
            // Загружаем CacheHelper перед использованием
            if (!class_exists(CacheHelper::class, false)) {
                ClassLoaderHelper::ensureLoaded(CacheHelper::class);
            }
            CacheHelper::forget($cacheKey);
        }

        return $installedCount;
    }

    public function getActivePlugins(): array
    {
        // Загружаем PluginConfigManager перед использованием
        if (!class_exists(PluginConfigManager::class, false)) {
            ClassLoaderHelper::ensureLoaded(PluginConfigManager::class);
        }

        try {
            // Получаем все установленные плагины из конфигурации
            $allPlugins = PluginConfigManager::loadConfig();
            $activeSlugs = [];

            foreach ($allPlugins as $slug => $status) {
                if ($status === 'active') {
                    $activeSlugs[] = $slug;
                }
            }

            $activePlugins = [];
            foreach ($activeSlugs as $slug) {
                if (isset($this->plugins[$slug])) {
                    $activePlugins[$slug] = $this->plugins[$slug];
                }
            }

            return $activePlugins;
        } catch (Exception $e) {
            try {
                Log::Error('Помилка отримання активних плагінів', ['exception' => $e]);
            } catch (Throwable $logError) {
                // Ignore logging errors
            }
            return [];
        }
    }

    public function installPlugin(string $pluginSlug): bool
    {
        try {
            $lifecycle = $this->getLifecycle();
            $result = $lifecycle->install($pluginSlug);
            // Сохраняем ошибку для доступа через getLastInstallError
            if (!$result && $lifecycle instanceof ApplicationPluginLifecycleService) {
                $this->lastInstallError = $lifecycle->getLastInstallError();
            } else {
                $this->lastInstallError = null;
            }
            return $result;
        } catch (Exception $e) {
            try {
                Log::Error('Помилка встановлення плагіна', ['exception' => $e]);
            } catch (Throwable $logError) {
                // Ignore logging errors
            }
            $this->lastInstallError = null;
            return false;
        }
    }

    /**
     * Отримати останню помилку встановлення плагіна
     *
     * @return string|null
     */
    public function getLastInstallError(): ?string
    {
        return $this->lastInstallError;
    }

    public function uninstallPlugin(string $pluginSlug): bool
    {
        try {
            try {
                Log::Debug('PluginManager::uninstallPlugin: Starting uninstallation', [
                    'plugin_slug' => $pluginSlug,
                ]);
            } catch (Throwable $e) {
                // Ignore logging errors
            }

            $plugin = $this->getPlugin($pluginSlug);
            if ($plugin instanceof BasePlugin && method_exists($plugin, 'uninstall')) {
                try {
                    Log::Debug('PluginManager::uninstallPlugin: Calling plugin->uninstall()', [
                        'plugin_slug' => $pluginSlug,
                    ]);
                } catch (Throwable $e) {
                    // Ignore logging errors
                }
                $plugin->uninstall();
            }

            try {
                Log::Debug('PluginManager::uninstallPlugin: Calling getLifecycle()->uninstall()', [
                    'plugin_slug' => $pluginSlug,
                ]);
            } catch (Throwable $e) {
                // Ignore logging errors
            }

            $result = $this->getLifecycle()->uninstall($pluginSlug);

            if ($result) {
                try {
                    Log::Debug('PluginManager::uninstallPlugin: Removing plugin hooks and from memory', [
                        'plugin_slug' => $pluginSlug,
                    ]);
                } catch (Throwable $e) {
                    // Ignore logging errors
                }
                $this->removePluginHooks($pluginSlug);
                unset($this->plugins[$pluginSlug]);

                try {
                    Log::Info('PluginManager::uninstallPlugin: Plugin uninstalled successfully', [
                        'plugin_slug' => $pluginSlug,
                    ]);
                } catch (Throwable $e) {
                    // Ignore logging errors
                }

                return true;
            }

            try {
                Log::Warning('PluginManager::uninstallPlugin: getLifecycle()->uninstall() returned false', [
                    'plugin_slug' => $pluginSlug,
                ]);
            } catch (Throwable $e) {
                // Ignore logging errors
            }

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

    private function deletePluginDirectory(string $dir): bool
    {
        // Используем ResourceCleanupHelper для удаления директории
        return ResourceCleanupHelper::deleteDirectory($dir);
    }

    /**
     * Валідація залежностей плагіна перед активацією
     *
     * @param string $pluginSlug Слаг плагіна
     * @return array<string, string> Масив помилок (порожній якщо все ОК)
     */
    public function validatePluginDependencies(string $pluginSlug): array
    {
        $plugin = $this->getPluginInstance($pluginSlug);

        if (!$plugin instanceof BasePlugin) {
            return ['general' => 'Плагін не знайдено'];
        }

        return $plugin->getDependencyErrors();
    }

    /**
     * Перевірка сумісності плагіна з ядром
     *
     * @param string $pluginSlug Слаг плагіна
     * @return array<string, mixed> Результат перевірки сумісності
     */
    public function checkPluginCompatibility(string $pluginSlug): array
    {
        // Перевіряємо, чи доступний PluginCompatibilityChecker
        if (!class_exists('Flowaxy\Support\Validators\PluginCompatibilityChecker')) {
            return [
                'compatible' => true,
                'errors' => [],
                'warnings' => ['Система перевірки сумісності недоступна'],
            ];
        }

        try {
            // Завантажуємо конфігурацію плагіна
            $pluginConfig = $this->getPluginConfig($pluginSlug);

            if (empty($pluginConfig)) {
                return [
                    'compatible' => false,
                    'errors' => ['Конфігурація плагіна не знайдена'],
                ];
            }

            // Виконуємо перевірку сумісності
            return \Flowaxy\Support\Validators\PluginCompatibilityChecker::getCompatibilityReport($pluginConfig);
        } catch (\Exception $e) {
            try {
                Log::Error("Помилка перевірки сумісності плагіна", ['exception' => $e, 'plugin_slug' => $pluginSlug]);
            } catch (Throwable $logError) {
                // Ignore logging errors
            }

            return [
                'compatible' => false,
                'errors' => ['Помилка перевірки сумісності: ' . $e->getMessage()],
            ];
        }
    }

    /**
     * Отримання конфігурації плагіна
     *
     * @param string $pluginSlug Слаг плагіна
     * @return array<string, mixed>
     */
    private function getPluginConfig(string $pluginSlug): array
    {
        try {
            $config = \Flowaxy\Support\Helpers\PluginMetadataHelper::readMetadata($pluginSlug);
            return is_array($config) ? $config : [];
        } catch (\Throwable $e) {
            return [];
        }
    }

    /**
     * Автоматичне встановлення залежностей плагіна
     *
     * @param string $pluginSlug Слаг плагіна
     * @return array<string, bool> Результати встановлення (ключ - slug залежності, значення - успіх)
     */
    public function installDependencies(string $pluginSlug): array
    {
        $plugin = $this->getPluginInstance($pluginSlug);

        if (!$plugin instanceof BasePlugin) {
            return [];
        }

        $dependencies = $plugin->getDependencies();
        $results = [];

        foreach ($dependencies as $dependency) {
            $depSlug = is_array($dependency) ? ($dependency['slug'] ?? '') : $dependency;

            if (empty($depSlug)) {
                continue;
            }

            // Перевіряємо, чи вже встановлений
            if ($this->isPluginInstalled($depSlug)) {
                $results[$depSlug] = true;
                continue;
            }

            // Спробуємо встановити
            try {
                $results[$depSlug] = $this->installPlugin($depSlug);

                // Якщо встановлено, активуємо
                if ($results[$depSlug]) {
                    $this->activatePlugin($depSlug);
                }
            } catch (Exception $e) {
                $results[$depSlug] = false;
                try {
                    Log::Error("Помилка встановлення залежності", ['exception' => $e, 'plugin_slug' => $pluginSlug, 'dependency' => $depSlug]);
                } catch (Throwable $logError) {
                    // Ignore logging errors
                }
            }
        }

        return $results;
    }

    public function activatePlugin(string $pluginSlug, bool $autoInstallDependencies = false): bool
    {
        try {
            try {
                Log::Debug('PluginManager::activatePlugin: Starting activation', [
                    'plugin_slug' => $pluginSlug,
                ]);
            } catch (Throwable $e) {
                // Ignore logging errors
            }

            // Проверяем, что плагин установлен
            $isInstalled = $this->isPluginInstalled($pluginSlug);
            try {
                Log::Debug('PluginManager::activatePlugin: Checking if plugin is installed', [
                    'plugin_slug' => $pluginSlug,
                    'is_installed' => $isInstalled,
                ]);
            } catch (Throwable $e) {
                // Ignore logging errors
            }

            if (!$isInstalled) {
                try {
                    Log::Warning("Неможливо активувати плагін - плагін не встановлений", [
                        'plugin_slug' => $pluginSlug,
                    ]);
                } catch (Throwable $e) {
                    // Ignore logging errors
                }
                return false;
            }

            // Проверка capabilities при активации (ТОЛЬКО здесь, не в бизнес-коде)
            try {
                $capabilityManager = $this->getCapabilityManager();
                if ($capabilityManager !== null) {
                    $pluginConfig = $this->getPluginConfig($pluginSlug);
                    if ($pluginConfig !== null && !empty($pluginConfig)) {
                        $declaredCapabilities = $capabilityManager->extractDeclaredCapabilities($pluginConfig);
                        if (!empty($declaredCapabilities) && !$capabilityManager->checkCapabilitiesOnActivation($pluginSlug, $declaredCapabilities)) {
                            // Логируем предупреждение, но не блокируем активацию
                            try {
                                Log::Warning("Попередження при активації плагіна - відсутні необхідні capabilities", [
                                    'plugin_slug' => $pluginSlug,
                                    'declared_capabilities' => $declaredCapabilities,
                                ]);
                            } catch (Throwable $e) {
                                // Ignore logging errors
                            }
                            // Не блокируем активацию, только логируем
                        }
                    }
                }
            } catch (Throwable $e) {
                try {
                    Log::Warning('PluginManager::activatePlugin: Error checking capabilities', [
                        'plugin_slug' => $pluginSlug,
                        'error' => $e->getMessage(),
                    ]);
                } catch (Throwable $logError) {
                    // Ignore logging errors
                }
            }

            // Перевірка сумісності з ядром перед активацією
            try {
                $compatibility = $this->checkPluginCompatibility($pluginSlug);
                if (!$compatibility['compatible']) {
                    // Логируем предупреждение, но не блокируем активацию для совместимости
                    try {
                        Log::Warning("Попередження при активації плагіна - перевірка сумісності не пройдена", [
                            'plugin_slug' => $pluginSlug,
                            'errors' => $compatibility['errors'] ?? [],
                            'warnings' => $compatibility['warnings'] ?? [],
                        ]);
                    } catch (Throwable $e) {
                        // Ignore logging errors
                    }
                    // Не блокируем активацию, только логируем
                }
            } catch (Throwable $e) {
                try {
                    Log::Warning('PluginManager::activatePlugin: Error checking compatibility', [
                        'plugin_slug' => $pluginSlug,
                        'error' => $e->getMessage(),
                    ]);
                } catch (Throwable $logError) {
                    // Ignore logging errors
                }
            }

            // Валідація залежностей перед активацією
            try {
                $dependencyErrors = $this->validatePluginDependencies($pluginSlug);

                if (!empty($dependencyErrors)) {
                    // Якщо дозволено автоматичне встановлення залежностей
                    if ($autoInstallDependencies) {
                        $installResults = $this->installDependencies($pluginSlug);

                        // Перевіряємо, чи всі залежності встановлені
                        $dependencyErrors = $this->validatePluginDependencies($pluginSlug);
                    }

                    // Логируем предупреждение о зависимостях, но не блокируем активацию
                    if (!empty($dependencyErrors)) {
                        try {
                            Log::Warning("Попередження при активації плагіна - відсутні залежності", [
                                'plugin_slug' => $pluginSlug,
                                'errors' => $dependencyErrors,
                            ]);
                        } catch (Throwable $e) {
                            // Ignore logging errors
                        }
                        // Не блокируем активацию, только логируем
                    }
                }
            } catch (Throwable $e) {
                try {
                    Log::Warning('PluginManager::activatePlugin: Error validating dependencies', [
                        'plugin_slug' => $pluginSlug,
                        'error' => $e->getMessage(),
                    ]);
                } catch (Throwable $logError) {
                    // Ignore logging errors
                }
            }

            try {
                Log::Debug('PluginManager::activatePlugin: Calling getLifecycle()->activate()', [
                    'plugin_slug' => $pluginSlug,
                ]);
            } catch (Throwable $e) {
                // Ignore logging errors
            }

            $lifecycle = $this->getLifecycle();
            if (!$lifecycle) {
                try {
                    Log::Error('PluginManager::activatePlugin: getLifecycle() returned null', [
                        'plugin_slug' => $pluginSlug,
                    ]);
                } catch (Throwable $e) {
                    // Ignore logging errors
                }
                return false;
            }

            $result = $lifecycle->activate($pluginSlug);
            if (! $result) {
                try {
                    Log::Error('PluginManager::activatePlugin: getLifecycle()->activate() returned false', [
                        'plugin_slug' => $pluginSlug,
                    ]);
                } catch (Throwable $e) {
                    // Ignore logging errors
                }
                return false;
            }

            try {
                Log::Debug('PluginManager::activatePlugin: getLifecycle()->activate() returned true', [
                    'plugin_slug' => $pluginSlug,
                ]);
            } catch (Throwable $e) {
                // Ignore logging errors
            }

            $plugin = $this->getPluginInstance($pluginSlug);

            if ($plugin instanceof BasePlugin) {
                if (method_exists($plugin, 'activate')) {
                    $plugin->activate();
                }

                if (method_exists($plugin, 'init')) {
                    try {
                        $plugin->init();
                    } catch (Exception $e) {
                        if (function_exists('logError')) {
                            Log::Error("PluginManager: Plugin init error after activation", ['plugin_slug' => $pluginSlug, 'error' => $e->getMessage(), 'exception' => $e]);
                        } else {
                            Log::Error("Plugin init error for {$pluginSlug} after activation: " . $e->getMessage(), ['exception' => $e]);
                        }
                    }
                }
            }

            return true;
        } catch (Exception $e) {
            Log::Error('PluginManager: Plugin activation error', ['error' => $e->getMessage(), 'exception' => $e]);
            return false;
        }
    }

    public function deactivatePlugin(string $pluginSlug): bool
    {
        try {
            $plugin = $this->getPluginInstance($pluginSlug);
            if ($plugin instanceof BasePlugin && method_exists($plugin, 'deactivate')) {
                $plugin->deactivate();
            }

            $result = $this->getLifecycle()->deactivate($pluginSlug);
            if (! $result) {
                return false;
            }

            $this->removePluginHooks($pluginSlug);

            if (isset($this->plugins[$pluginSlug])) {
                unset($this->plugins[$pluginSlug]);
            }

            return true;
        } catch (Exception $e) {
            try {
                Log::Error('Помилка деактивації плагіна', ['exception' => $e]);
            } catch (Throwable $logError) {
                // Ignore logging errors
            }
            return false;
        }
    }

    /**
     * Перевірка активності плагіна
     */
    public function isPluginActive(string $pluginSlug): bool
    {
        return ! empty($pluginSlug) && isset($this->plugins[$pluginSlug]);
    }

    /**
     * Перевірка, чи встановлений плагін
     *
     * @param string $pluginSlug Слаг плагіна
     * @return bool
     */
    public function isPluginInstalled(string $pluginSlug): bool
    {
        if (empty($pluginSlug)) {
            return false;
        }

        try {
            if (class_exists(\Flowaxy\Infrastructure\Config\PluginConfigManager::class)) {
                return \Flowaxy\Infrastructure\Config\PluginConfigManager::isInstalled($pluginSlug);
            }
        } catch (Throwable $e) {
            try {
                Log::Error("Помилка перевірки встановлення плагіна", ['exception' => $e, 'plugin_slug' => $pluginSlug]);
            } catch (Throwable $logError) {
                // Ignore logging errors
            }
        }

        return false;
    }

    /**
     * Отримання конкретного плагіна
     *
     * @return BasePlugin|object|null
     */
    public function getPlugin(string $pluginSlug)
    {
        return $this->plugins[$pluginSlug] ?? $this->getPluginInstance($pluginSlug);
    }

    public function getPluginSetting(string $pluginSlug, string $settingKey, $default = null)
    {
        try {
            if (class_exists(\Flowaxy\Infrastructure\Config\PluginSettingsManager::class)) {
                return \Flowaxy\Infrastructure\Config\PluginSettingsManager::getValue($pluginSlug, $settingKey, $default);
            }
        } catch (Throwable $e) {
            try {
                Log::Error('Помилка отримання налаштування плагіна', ['exception' => $e]);
            } catch (Throwable $logError) {
                // Ignore logging errors
            }
        }

        return $default;
    }

    public function setPluginSetting(string $pluginSlug, string $settingKey, $value): bool
    {
        try {
            if (class_exists(\Flowaxy\Infrastructure\Config\PluginSettingsManager::class)) {
                return \Flowaxy\Infrastructure\Config\PluginSettingsManager::setValue($pluginSlug, $settingKey, $value);
            }
        } catch (Exception $e) {
            try {
                Log::Error('Помилка збереження налаштування плагіна', ['exception' => $e]);
            } catch (Throwable $logError) {
                // Ignore logging errors
            }
        }

        return false;
    }

    private function removePluginHooks(string $pluginSlug): void
    {
        if (empty($pluginSlug)) {
            return;
        }

        $className = $this->getPluginClassName($pluginSlug);
        $allHooks = $this->hookManager->getAllHooks();

        foreach ($allHooks as $hookName => $hooks) {
            foreach ($hooks as $hook) {
                $callback = $hook['callback'] ?? null;
                if ($callback === null) {
                    continue;
                }

                if (is_array($callback)) {
                    if (isset($callback[0]) && is_object($callback[0])) {
                        $objectClass = get_class($callback[0]);
                        if ($objectClass === $className || str_contains($objectClass, $pluginSlug)) {
                            $this->hookManager->remove($hookName, $callback);
                        }
                    }
                } elseif (is_string($callback) && (str_contains($callback, $className) || str_contains($callback, $pluginSlug))) {
                    $this->hookManager->remove($hookName, $callback);
                }
            }
        }

        foreach ($this->hooks as $hookName => $hooks) {
            $filteredHooks = array_filter($hooks, function ($hook) use ($className, $pluginSlug) {
                if (is_array($hook['callback'])) {
                    if (isset($hook['callback'][0])) {
                        $object = $hook['callback'][0];
                        if (is_object($object)) {
                            $objectClass = get_class($object);
                            if ($objectClass === $className || str_contains($objectClass, $pluginSlug)) {
                                return false;
                            }
                        }
                    }
                }

                return true;
            });

            $this->hooks[$hookName] = array_values($filteredHooks);

            if (empty($this->hooks[$hookName])) {
                unset($this->hooks[$hookName]);
            }
        }
    }

    private function getEngineDir(): string
    {
        return PathResolver::engine();
    }

    private function getProjectRoot(): string
    {
        return PathResolver::root();
    }

    /**
     * Отримання підключення до БД
     *
     * @return PDO|null
     */
    private function getDB(): ?PDO
    {
        // Проверяем наличие констант БД перед попыткой подключения
        if (!defined('DB_HOST') || empty(DB_HOST) || !defined('DB_NAME') || empty(DB_NAME)) {
            return null;
        }

        // Убеждаемся, что DatabaseHelper загружен
        if (!class_exists(\Flowaxy\Support\Helpers\DatabaseHelper::class)) {
            $helperFile = \Flowaxy\Core\System\PathResolver::flowaxy() . DS . 'Support' . DS . 'Helpers' . DS . 'DatabaseHelper.php';
            if (file_exists($helperFile)) {
                require_once $helperFile;
            }
        }

        try {
            return DatabaseHelper::getConnection(false);
        } catch (\Throwable $e) {
            // Игнорируем ошибки подключения к БД
            return null;
        }
    }

    private function getLifecycle(): PluginLifecycleInterface
    {
        if ($this->lifecycle instanceof PluginLifecycleInterface) {
            return $this->lifecycle;
        }

        if (class_exists(\Flowaxy\Support\Facades\App::class)) {
            try {
                $app = \Flowaxy\Support\Facades\App::container();
                if ($app->has(PluginLifecycleInterface::class)) {
                    $lifecycle = $app->make(PluginLifecycleInterface::class);

                    // Проверяем, что контейнер вернул объект, а не Closure
                    if ($lifecycle instanceof PluginLifecycleInterface) {
                        $this->lifecycle = $lifecycle;
                        return $this->lifecycle;
                    } else {
                        if (function_exists('logWarning')) {
                            Log::Warning('PluginManager::getLifecycle: Container returned non-PluginLifecycleInterface object', [
                                'type' => is_object($lifecycle) ? get_class($lifecycle) : gettype($lifecycle),
                            ]);
                        }
                        // Fallback ниже
                    }
                }
            } catch (Exception $e) {
                // fallback below
            }
        }

        $repository = new PluginRepository();
        $filesystem = new PluginFilesystem();
        $cache = new PluginCacheManager();

        $installer = new InstallPluginService($repository);
        $activator = new ActivatePluginService($repository);
        $deactivator = new DeactivatePluginService($repository);
        $uninstaller = new UninstallPluginService($repository);

        $this->lifecycle = new ApplicationPluginLifecycleService(
            $filesystem,
            $cache,
            $installer,
            $activator,
            $deactivator,
            $uninstaller
        );

        return $this->lifecycle;
    }

    /**
     * Получить менеджер capabilities
     *
     * @return PluginCapabilityManager|null
     */
    private function getCapabilityManager(): ?PluginCapabilityManager
    {
        if ($this->capabilityManager !== null) {
            return $this->capabilityManager;
        }

        try {
            // Пытаемся получить из контейнера
            if (class_exists(\Flowaxy\Support\Facades\App::class)) {
                $app = \Flowaxy\Support\Facades\App::container();
                if ($app->has(PluginCapabilityInterface::class)) {
                    $capabilityChecker = $app->make(PluginCapabilityInterface::class);
                    if ($capabilityChecker instanceof PluginCapabilityInterface) {
                        $this->capabilityManager = new PluginCapabilityManager($capabilityChecker);
                        return $this->capabilityManager;
                    }
                }
            }
        } catch (Exception $e) {
            // Fallback ниже
        }

        // Fallback: создаем напрямую
        try {
            // Используем getInstance() вместо прямого создания, так как конструктор приватный
            $database = \Flowaxy\Infrastructure\Persistence\Database\Database::getInstance();
            $repository = new \Flowaxy\Infrastructure\Persistence\Repositories\PluginCapabilityRepository($database);
            $capabilityChecker = new \Flowaxy\Infrastructure\Security\PluginCapabilityChecker($repository);
            $this->capabilityManager = new PluginCapabilityManager($capabilityChecker);
            return $this->capabilityManager;
        } catch (Exception $e) {
            return null;
        }
    }
}

function addHook(string $hookName, callable $callback, int $priority = 10): void
{
    $manager = PluginManager::getInstance();
    if ($manager) {
        $manager->addHook($hookName, $callback, $priority);
    } else {
        hooks()->filter($hookName, $callback, $priority);
    }
}

function hasHook(string $hookName): bool
{
    $manager = PluginManager::getInstance();

    return $manager ? $manager->hasHook($hookName) : hooks()->has($hookName);
}

function addFilter(string $hookName, callable $callback, int $priority = 10, ?callable $condition = null): void
{
    hooks()->filter($hookName, $callback, $priority);
}

/**
 * @param mixed $data
 * @param mixed ...$args
 * @return mixed
 */
function applyFilter(string $hookName, $data = null, ...$args)
{
    $context = [];
    if (! empty($args)) {
        $context = is_array($args[0]) ? $args[0] : $args;
    }

    return Hooks::apply($hookName, $data, $context);
}

/**
 * Alias for applyFilter - applies a filter hook
 *
 * @param string $hookName
 * @param mixed $data
 * @param mixed ...$args
 * @return mixed
 */
function hook_apply(string $hookName, $data = null, ...$args)
{
    return applyFilter($hookName, $data, ...$args);
}

function addAction(string $hookName, callable $callback, int $priority = 10, ?callable $condition = null): void
{
    hooks()->on($hookName, $callback, $priority);
}

function doAction(string $hookName, ...$args): void
{
    Hooks::dispatch($hookName, ...$args);
}

function removeHook(string $hookName, ?callable $callback = null): bool
{
    hooks()->remove($hookName, $callback);

    return true;
}

/**
 * Отримання менеджера хуків
 *
 * @return HookManagerInterface
 */
function hooks(): HookManagerInterface
{
    // Завантажуємо HookRegistryInterface ПЕРЕД HookManagerInterface (HookManagerInterface залежить від нього)
    // Используем ClassLoaderHelper, если он доступен
    if (class_exists(\Flowaxy\Support\Helpers\ClassLoaderHelper::class, false)) {
        \Flowaxy\Support\Helpers\ClassLoaderHelper::ensureLoaded('Flowaxy\Core\Contracts\HookRegistryInterface');
        \Flowaxy\Support\Helpers\ClassLoaderHelper::ensureLoaded('Flowaxy\Core\Contracts\HookManagerInterface');
    } else {
        // Fallback: загружаем напрямую
        $flowaxyDir = PathResolver::flowaxy();

        if (!\interface_exists('Flowaxy\Core\Contracts\HookRegistryInterface')) {
            $hookRegistryInterfaceFile = $flowaxyDir . DS . 'Core' . DS . 'Contracts' . DS . 'HookRegistryInterface.php';
            if (file_exists($hookRegistryInterfaceFile) && is_readable($hookRegistryInterfaceFile)) {
                require_once $hookRegistryInterfaceFile;
            }
        }

        if (!\interface_exists('Flowaxy\Core\Contracts\HookManagerInterface')) {
            $hookManagerInterfaceFile = $flowaxyDir . DS . 'Core' . DS . 'Contracts' . DS . 'HookManagerInterface.php';
            if (file_exists($hookManagerInterfaceFile) && is_readable($hookManagerInterfaceFile)) {
                require_once $hookManagerInterfaceFile;
            }
        }
    }

    // Спробуємо отримати з контейнера
    $container = $GLOBALS['container'] ?? $GLOBALS['engineContainer'] ?? null;
    if ($container && $container->has(\Flowaxy\Core\Contracts\HookManagerInterface::class)) {
        return $container->make(\Flowaxy\Core\Contracts\HookManagerInterface::class);
    }

    // Завантажуємо залежності HookManager перед його створенням
    // HookRegistry та HookPerformanceMonitor потрібні для HookManager
    if (!\class_exists('Flowaxy\Core\Hooks\HookRegistry')) {
        $hookRegistryFile = $flowaxyDir . DS . 'Core' . DS . 'Hooks' . DS . 'HookRegistry.php';
        if (\file_exists($hookRegistryFile) && \is_readable($hookRegistryFile)) {
            require_once $hookRegistryFile;
        }
    }

    if (!\class_exists('Flowaxy\Core\Hooks\HookPerformanceMonitor')) {
        $hookPerformanceMonitorFile = $flowaxyDir . DS . 'Core' . DS . 'Hooks' . DS . 'HookPerformanceMonitor.php';
        if (\file_exists($hookPerformanceMonitorFile) && \is_readable($hookPerformanceMonitorFile)) {
            require_once $hookPerformanceMonitorFile;
        }
    }

    // Fallback: створюємо новий екземпляр
    $hookManagerFile = $flowaxyDir . DS . 'Core' . DS . 'Hooks' . DS . 'HookManager.php';
    if (\file_exists($hookManagerFile) && !\class_exists('Flowaxy\Core\Hooks\HookManager')) {
        require_once $hookManagerFile;
    }

    if (\class_exists('Flowaxy\Core\Hooks\HookManager')) {
        return new \Flowaxy\Core\Hooks\HookManager();
    }

    // Критична ситуація, але кидаємо звичайний Exception, щоб уникнути проблем static analysis
    throw new Exception('HookManager not available');
}

function hookManager(): HookManagerInterface
{
    return hooks();
}
