<?php

declare(strict_types=1);

namespace Flowaxy\Support\Helpers;

use Flowaxy\Core\System\PathResolver;
use Throwable;

use function class_exists;
use function dirname;
use function file_exists;
use function interface_exists;
use function is_readable;
use function str_replace;
use function str_starts_with;
use function substr;
use const DS;

// Хелпер для безпечної завантаження класів
// Централізовані методи для завантаження класів з fallback механізмами
final class ClassLoaderHelper
{
    // Перевірка та завантаження класу, якщо він не завантажений
    public static function ensureLoaded(string $className): bool
    {
        // Якщо клас вже завантажений, повертаємо true
        if (class_exists($className, false) || interface_exists($className, false)) {
            return true;
        }

        // Визначаємо шлях до файлу класу
        $filePath = self::getClassFilePath($className);
        if ($filePath === null) {
            return false;
        }

        // Завантажуємо файл, якщо він існує
        return self::loadIfExists($filePath);
    }

    // Завантаження файлу, якщо він існує та доступний для читання
    public static function loadIfExists(string $filePath): bool
    {
        if (!file_exists($filePath)) {
            return false;
        }

        if (!is_readable($filePath)) {
            return false;
        }

        try {
            require_once $filePath;
            return true;
        } catch (Throwable $e) {
            // Помилка при завантаженні файлу
            return false;
        }
    }

    // Завантаження менеджера за ім'ям
    public static function loadManager(string $managerName): bool
    {
        $className = 'Flowaxy\Support\Managers\\' . $managerName;
        return self::ensureLoaded($className);
    }

    // Визначення шляху до файлу класу за його namespace
    public static function getClassFilePath(string $className): ?string
    {
        // Перевіряємо, чи це клас з namespace Flowaxy
        if (!str_starts_with($className, 'Flowaxy\\')) {
            return null;
        }

        // Видаляємо префікс Flowaxy\
        $relativePath = substr($className, 8); // 8 = strlen('Flowaxy\')

        // Замінюємо \ на DS
        $relativePath = str_replace('\\', DS, $relativePath);

        // Додаємо розширення .php
        $relativePath .= '.php';

        // Спочатку пробуємо через PathResolver
        if (class_exists(PathResolver::class)) {
            try {
                $flowaxyDir = PathResolver::flowaxy();
                $fullPath = $flowaxyDir . DS . $relativePath;

                if (file_exists($fullPath)) {
                    return $fullPath;
                }
            } catch (Throwable $e) {
                // PathResolver не доступний, продовжуємо до fallback
            }
        }

        // Fallback: використовуємо відносний шлях від поточного файлу
        // Припускаємо, що поточний файл знаходиться в flowaxy/Support/Helpers/
        $currentDir = __DIR__; // flowaxy/Support/Helpers/
        $flowaxyDir = dirname(dirname($currentDir)); // flowaxy/
        $fullPath = $flowaxyDir . DS . $relativePath;

        if (file_exists($fullPath)) {
            return $fullPath;
        }

        return null;
    }

    // Завантаження кількох класів одночасно
    public static function ensureLoadedMultiple(array $classNames): array
    {
        $results = [];
        foreach ($classNames as $className) {
            $results[$className] = self::ensureLoaded($className);
        }

        return $results;
    }

    // Перевірка, чи завантажений клас
    public static function isLoaded(string $className): bool
    {
        return class_exists($className, false) || interface_exists($className, false);
    }

    // Безпечно завантажити клас з обробкою помилок
    public static function safeLoad(string $className, mixed $defaultValue = false): mixed
    {
        return ExceptionHandler::safeExecute(
            fn() => self::ensureLoaded($className),
            $defaultValue,
            "Помилка завантаження класу: {$className}",
            ['class' => $className]
        );
    }

    // Завантажити клас та його залежності
    public static function loadWithDependencies(string $className, array $dependencies = []): bool
    {
        // Спочатку завантажуємо залежності
        foreach ($dependencies as $dependency) {
            if (!self::ensureLoaded($dependency)) {
                SafeLogger::warning("Не вдалося завантажити залежність: {$dependency}", [
                    'dependency' => $dependency,
                    'target_class' => $className,
                ]);
                return false;
            }
        }

        // Потім завантажуємо основний клас
        return self::ensureLoaded($className);
    }

    // Завантажити репозиторій за ім'ям
    public static function loadRepository(string $repositoryName): bool
    {
        $className = 'Flowaxy\Infrastructure\Persistence\Repositories\\' . $repositoryName;
        return self::ensureLoaded($className);
    }

    // Завантажити сервіс за ім'ям
    public static function loadService(string $serviceName, ?string $namespace = null): bool
    {
        if ($namespace === null) {
            $namespace = 'Flowaxy\Core\System';
        }
        $className = $namespace . '\\' . $serviceName;
        return self::ensureLoaded($className);
    }

    // Завантажити фасад за ім'ям
    public static function loadFacade(string $facadeName): bool
    {
        $className = 'Flowaxy\Support\Facades\\' . $facadeName;
        return self::ensureLoaded($className);
    }
}
