<?php

declare(strict_types=1);

namespace Flowaxy\Support\Helpers;

use Flowaxy\Core\System\PathResolver;
use Flowaxy\Support\Managers\ThemeManager;
use Flowaxy\Support\Managers\PluginManager;
use Flowaxy\Support\Managers\RoleManager;
use Flowaxy\Infrastructure\Cache\Cache;
use Flowaxy\Interface\Http\Request;
use Flowaxy\Support\Facades\Theme;
use Flowaxy\Support\Facades\Plugin;
use Flowaxy\Support\Facades\Role;
use Flowaxy\Support\Facades\Cache as CacheFacade;
use Throwable;

use function class_exists;
use function file_exists;
use function is_readable;
use function is_a;
use const DS;

// Хелпер для отримання менеджерів системи
// Централізовані методи для отримання менеджерів з fallback механізмами
// Оптимізовано для PHP 8.4+
final class ManagerHelper
{
    // Отримання менеджера тем
    /** @phpstan-ignore-next-line */
    public static function themeManager(): ?ThemeManager
    {
        // Спочатку пробуємо через фасад Theme
        if (class_exists(Theme::class)) {
            try {
                $manager = Theme::manager();
                /** @phpstan-ignore-next-line */
                if (is_a($manager, ThemeManager::class)) {
                    return $manager;
                }
            } catch (Throwable $e) {
                // Фасад не доступний, продовжуємо до fallback
            }
        }

        // Fallback: використовуємо getInstance() напрямую
        /** @phpstan-ignore-next-line */
        if (class_exists(ThemeManager::class)) {
            try {
                /** @var ThemeManager $manager */
                /** @phpstan-ignore-next-line */
                $manager = ThemeManager::getInstance();
                if ($manager instanceof ThemeManager) {
                    return $manager;
                }
            } catch (Throwable $e) {
                // getInstance() не спрацював
            }
        }

        // Останній fallback: завантажуємо клас вручну
        /** @phpstan-ignore-next-line */
        return self::loadManagerFromFile(
            /** @phpstan-ignore-next-line */
            ThemeManager::class,
            PathResolver::flowaxy() . DS . 'Support' . DS . 'Managers' . DS . 'ThemeManager.php'
        );
    }

    // Отримання менеджера плагінів
    public static function pluginManager(): ?PluginManager
    {
        // Спочатку пробуємо через фасад Plugin
        if (class_exists(Plugin::class)) {
            try {
                $manager = Plugin::manager();
                if ($manager instanceof PluginManager) {
                    return $manager;
                }
            } catch (Throwable $e) {
                // Фасад не доступний, продовжуємо до fallback
            }
        }

        // Fallback: використовуємо getInstance() напрямую
        if (class_exists(PluginManager::class)) {
            try {
                $manager = PluginManager::getInstance();
                if ($manager instanceof PluginManager) {
                    return $manager;
                }
            } catch (Throwable $e) {
                // getInstance() не спрацював
            }
        }

        // Останній fallback: завантажуємо клас вручну
        /** @phpstan-ignore-next-line */
        return self::loadManagerFromFile(
            /** @phpstan-ignore-next-line */
            PluginManager::class,
            PathResolver::flowaxy() . DS . 'Support' . DS . 'Managers' . DS . 'PluginManager.php'
        );
    }

    // Отримання менеджера ролей
    /** @phpstan-ignore-next-line */
    public static function roleManager(): ?RoleManager
    {
        // Спочатку пробуємо через фасад Role
        if (class_exists(Role::class)) {
            try {
                $manager = Role::manager();
                if ($manager instanceof RoleManager) {
                    return $manager;
                }
            } catch (Throwable $e) {
                // Фасад не доступний, продовжуємо до fallback
            }
        }

        // Fallback: використовуємо getInstance() напрямую
        /** @phpstan-ignore-next-line */
        if (class_exists(RoleManager::class)) {
            try {
                /** @var RoleManager $manager */
                /** @phpstan-ignore-next-line */
                $manager = RoleManager::getInstance();
                if ($manager instanceof RoleManager) {
                    return $manager;
                }
            } catch (Throwable $e) {
                // getInstance() не спрацював
            }
        }

        return null;
    }

    // Отримання менеджера кешу
    public static function cache(): ?Cache
    {
        // Спочатку пробуємо через фасад Cache
        if (class_exists(CacheFacade::class)) {
            try {
                $cache = CacheFacade::getInstance();
                if ($cache instanceof Cache) {
                    return $cache;
                }
            } catch (Throwable $e) {
                // Фасад не доступний, продовжуємо до fallback
            }
        }

        // Fallback: використовуємо getInstance() напрямую
        if (class_exists(Cache::class)) {
            try {
                $cache = Cache::getInstance();
                if ($cache instanceof Cache) {
                    return $cache;
                }
            } catch (Throwable $e) {
                // getInstance() не спрацював
            }
        }

        return null;
    }

    // Отримання об'єкта Request
    public static function request(): ?Request
    {
        // Використовуємо getInstance() напрямую
        if (class_exists(Request::class)) {
            try {
                $request = Request::getInstance();
                if ($request instanceof Request) {
                    return $request;
                }
            } catch (Throwable $e) {
                // getInstance() не спрацював
            }
        }

        return null;
    }

    // Завантаження менеджера з файлу (fallback механізм)
    /** @phpstan-ignore-next-line */
    private static function loadManagerFromFile(string $className, string $filePath): ThemeManager|PluginManager|null
    {
        if (!file_exists($filePath) || !is_readable($filePath)) {
            return null;
        }

        require_once $filePath; // Дозволено для динамічного завантаження fallback

        if (!class_exists($className)) {
            return null;
        }

        try {
            $manager = $className::getInstance();
            return is_a($manager, $className) ? $manager : null;
        } catch (Throwable $e) {
            // Не вдалося отримати інстанс
            return null;
        }
    }
}
