<?php

/**
 * Реєструє базові сервіси ядра у контейнері.
 *
 * @package Flowaxy\Core\System\Container
 * @version 1.0.0 Alpha prerelease
 */

declare(strict_types=1);

namespace Flowaxy\Core\System\Container;

use Flowaxy\Core\Contracts\ComponentRegistryInterface;
use Flowaxy\Core\Contracts\ContainerInterface;
use Flowaxy\Core\Contracts\FeatureFlagManagerInterface;
use Flowaxy\Core\Contracts\HookManagerInterface;
use Flowaxy\Core\Contracts\HookRegistryInterface;
use Flowaxy\Core\Contracts\LoggerInterface;
use Flowaxy\Core\Hooks\HookManager;
use Flowaxy\Core\Routing\RouterManager;
use Flowaxy\Core\System\ComponentRegistry;
use Flowaxy\Core\System\Container\ServiceProvider;
use Flowaxy\Core\System\FeatureFlagManager;
use Flowaxy\Infrastructure\Config\Config as ConfigInstance;
use Flowaxy\Infrastructure\Logging\Logger as LoggerInstance;
use Flowaxy\Infrastructure\Security\Hash as HashInstance;
use Flowaxy\Interface\Http\Request as RequestInstance;
use Flowaxy\Support\Facades\Log;
use Flowaxy\Support\Managers\SessionManager;

use function class_exists;

final class CoreServiceProvider extends ServiceProvider
{
    protected function registerBindings(): void
    {
        Log::Debug('CoreServiceProvider::registerBindings: Starting service registration');

        // Контейнер доступний також за своїм інтерфейсом
        $this->container->instance(ContainerInterface::class, $this->container);

        // Реєструємо HookManager ПЕРШИМ, оскільки інші сервіси можуть його використовувати
        $this->registerHookManager();

        $this->registerDatabase();
        $this->registerCache();
        $this->registerLogger();
        $this->registerConfig();

        // Регистрируем Security ВАЖНО: это критический сервис, должен быть зарегистрирован
        try {
            $this->registerSecurity();
        } catch (\Throwable $e) {
            // Логируем критическую ошибку, но продолжаем регистрацию других сервисов
            try {
                Log::Critical('CoreServiceProvider::registerBindings: Failed to register Security services', [
                    'error' => $e->getMessage(),
                    'trace' => $e->getTraceAsString()
                ]);
            } catch (\Throwable $logError) {
                // Игнорируем ошибки логирования
            }
        }

        $this->registerManagers();
        $this->registerHttpComponents();
        $this->registerComponentRegistry();
        $this->registerModuleManager();
        $this->registerTestService();
        $this->registerFeatureFlags();

        // Проверяем, что HashInstance зарегистрирован
        try {
            if (!$this->container->has(HashInstance::class)) {
                Log::Warning('CoreServiceProvider::registerBindings: HashInstance not registered after registerSecurity()', [
                    'HashInstance::class' => HashInstance::class,
                    'container_class' => get_class($this->container)
                ]);
            }
        } catch (\Throwable $e) {
            // Игнорируем ошибки проверки
        }

        Log::Info('CoreServiceProvider::registerBindings: All core services registered successfully');
    }

    private function registerDatabase(): void
    {
        // TODO: Update when Database is migrated
        if (class_exists('Database')) {
            $this->container->singleton('Database', static fn () => \Database::getInstance());
        }
        if (class_exists('DatabaseInterface')) {
            $this->container->singleton('DatabaseInterface', fn () => $this->container->make('Database'));
        }
    }

    private function registerCache(): void
    {
        // TODO: Update when Cache is migrated
        if (class_exists('Cache')) {
            $this->container->singleton('Cache', static fn () => \Cache::getInstance());
        }
    }

    private function registerLogger(): void
    {
        // ВАЖНО: LoggerInterface НЕ может быть lazy-singleton.
        // Текущая реализация lazy в контейнере возвращает proxy (class@anonymous),
        // который не реализует интерфейс и ломает строгие return types (например Log::instance(): LoggerInterface).
        $logger = LoggerInstance::getInstance();
        $this->container->instance(LoggerInstance::class, $logger);
        $this->container->instance(LoggerInterface::class, $logger);
    }

    private function registerHookManager(): void
    {
        // Створюємо один екземпляр HookManager і використовуємо його для всіх інтерфейсів
        // Це уникне циклічних залежностей
        $hookManager = new HookManager();
        $this->container->instance(HookManagerInterface::class, $hookManager);
        $this->container->instance(HookRegistryInterface::class, $hookManager);
        $this->container->instance(HookManager::class, $hookManager);
    }

    private function registerComponentRegistry(): void
    {
        $this->container->singleton(ComponentRegistryInterface::class, static fn () => new ComponentRegistry());
    }

    private function registerModuleManager(): void
    {
        // TODO: Update when ModuleManager is migrated
        if (class_exists('ModuleManager')) {
            $this->container->singleton('ModuleManager', function () {
                return new \ModuleManager(
                    $this->container,
                    $this->container->make(ComponentRegistryInterface::class)
                );
            });
        }
    }

    private function registerTestService(): void
    {
        // TODO: Update when TestService is migrated
        if (class_exists('TestService')) {
            $this->container->singleton('TestService', static fn () => new \TestService());
        }
    }

    private function registerConfig(): void
    {
        // TODO: Update when SystemConfig is migrated
        if (class_exists('SystemConfig')) {
            $this->container->singleton('SystemConfig', static fn () => \SystemConfig::getInstance());
        }
        $this->container->singleton(\Flowaxy\Infrastructure\Config\Config::class, static fn () => \Flowaxy\Infrastructure\Config\Config::getInstance());
    }

    private function registerSecurity(): void
    {
        // Регистрируем HashInstance для Hash facade
        // HashInstance не имеет зависимостей, поэтому безопасно создавать через new
        // Всегда регистрируем, так как это базовый сервис безопасности

        // Убеждаемся, что класс HashInstance загружен
        $hashInstanceClass = HashInstance::class;
        if (!class_exists($hashInstanceClass)) {
            // Пробуем загрузить через autoloader
            if (function_exists('spl_autoload_call')) {
                spl_autoload_call($hashInstanceClass);
            }

            // Если все еще не загружен, логируем ошибку
            if (!class_exists($hashInstanceClass)) {
                try {
                    Log::Error('CoreServiceProvider::registerSecurity: HashInstance class not found', [
                        'class' => $hashInstanceClass
                    ]);
                } catch (\Throwable $logError) {
                    // Игнорируем ошибки логирования
                }
                return; // Прерываем регистрацию, если класс не найден
            }
        }

        try {
            // Создаем экземпляр HashInstance сразу для немедленной регистрации
            $hashInstance = new HashInstance();

            // Регистрируем HashInstance как singleton через instance() для немедленной регистрации
            $this->container->instance($hashInstanceClass, $hashInstance);

            // Проверяем, что регистрация прошла успешно
            if (!$this->container->has($hashInstanceClass)) {
                throw new \RuntimeException("Failed to register HashInstance: container->has() returns false after instance() call");
            }

            // Также регистрируем по интерфейсу для совместимости
            if (interface_exists('Flowaxy\Contracts\Security\HashInterface')) {
                $this->container->singleton('Flowaxy\Contracts\Security\HashInterface', fn () => $this->container->make($hashInstanceClass));
            }

            // Логируем успешную регистрацию
            try {
                Log::Debug('CoreServiceProvider::registerSecurity: HashInstance registered successfully', [
                    'HashInstance::class' => $hashInstanceClass,
                    'container_has' => $this->container->has($hashInstanceClass),
                    'container_class' => get_class($this->container)
                ]);
            } catch (\Throwable $e) {
                // Игнорируем ошибки логирования
            }
        } catch (\Throwable $e) {
            // Логируем ошибку регистрации
            try {
                Log::Error('CoreServiceProvider::registerSecurity: Failed to register HashInstance', [
                    'error' => $e->getMessage(),
                    'class' => $hashInstanceClass,
                    'class_exists' => class_exists($hashInstanceClass),
                    'container_class' => get_class($this->container),
                    'container_has_method' => method_exists($this->container, 'has') ? 'yes' : 'no',
                    'trace' => $e->getTraceAsString()
                ]);
            } catch (\Throwable $logError) {
                // Игнорируем ошибки логирования
            }
            // НЕ пробрасываем исключение, чтобы не сломать инициализацию других сервисов
            // Но логируем критическую ошибку
        }
    }

    private function registerManagers(): void
    {
        // TODO: Update when Managers are migrated
        // Менеджери сховищ та сесій
        if (class_exists('CookieManager')) {
            $this->container->singleton('CookieManager', static fn () => \CookieManager::getInstance());
        }
        // Реєструємо SessionManager з повним ім'ям класу для фасада
        if (class_exists(SessionManager::class)) {
            $this->container->singleton(SessionManager::class, static fn () => SessionManager::getInstance());
            // Також реєструємо як 'SessionManager' для сумісності
            $this->container->singleton('SessionManager', fn () => $this->container->make(SessionManager::class));
        } elseif (class_exists('SessionManager')) {
            $this->container->singleton('SessionManager', static fn () => \SessionManager::getInstance());
        }
        if (class_exists('StorageManager')) {
            $this->container->singleton('StorageManager', static fn () => \StorageManager::getInstance());
        }

        // Менеджери системи
        if (class_exists('SettingsManager')) {
            $this->container->singleton('SettingsManager', static fn () => \SettingsManager::getInstance());
        }
        if (class_exists('RoleManager')) {
            $this->container->singleton('RoleManager', static fn () => \RoleManager::getInstance());
        }
        if (class_exists('ThemeManager')) {
            $this->container->singleton('ThemeManager', static fn () => \ThemeManager::getInstance());
        }
    }

    private function registerHttpComponents(): void
    {
        $this->container->singleton(RequestInstance::class, static fn () => RequestInstance::getInstance());
        // TODO: Update when ModalHandler is migrated
        if (class_exists('ModalHandler')) {
            $this->container->singleton('ModalHandler', static fn () => \ModalHandler::getInstance());
        }
        // RouterManager не должен быть lazy, так как Facade::manager() требует точный тип RouterManager
        $this->container->singleton(RouterManager::class, static fn () => RouterManager::getInstance(), false);
    }

    private function registerFeatureFlags(): void
    {
        // TODO: Update when FeatureFlagManager is migrated
        if (class_exists(FeatureFlagManager::class)) {
            $this->container->singleton(FeatureFlagManagerInterface::class, function () {
                $logger = $this->container->has(LoggerInterface::class)
                    ? $this->container->make(LoggerInterface::class)
                    : null;

                return new FeatureFlagManager($logger);
            });

            $this->container->singleton('FeatureFlagManager', fn () => $this->container->make(FeatureFlagManagerInterface::class));
        }
    }
}
