<?php

/**
 * Глобальные функции для работы с ролями и правами
 *
 * @package Flowaxy\Support\Helpers
 * @version 1.0.0 Alpha prerelease
 */

declare(strict_types=1);

use Flowaxy\Support\Facades\Session;
use Flowaxy\Support\Facades\App;
use Flowaxy\Support\Facades\Log;
use Flowaxy\Domain\User\Services\AuthorizationService;
use Flowaxy\Domain\User\Services\AdminRoleRepositoryInterface;
use Flowaxy\Infrastructure\Persistence\Repositories\AdminRoleRepository;
use Flowaxy\Support\Managers\RoleManager;
use Flowaxy\Support\Facades\Role;

/**
 * Получение сервиса авторизации администраторов
 */
if (!function_exists('adminAuthorizationService')) {
    /**
     * @return object|null
     * @phpstan-ignore-next-line
     */
    function adminAuthorizationService()
    {
        static $resolving = false;
        static $instance = null;

        if ($resolving) {
            // Защита от циклической зависимости
            return null;
        }

        if ($instance !== null) {
            return $instance;
        }

        /** @phpstan-ignore-next-line */
        if (!class_exists(AuthorizationService::class)) {
            return null;
        }

        try {
            $resolving = true;

            if (class_exists(App::class)) {
                $container = App::container();
                // Проверяем, есть ли сервис в контейнере
                /** @phpstan-ignore-next-line */
                if ($container->has(AuthorizationService::class)) {
                    /** @phpstan-ignore-next-line */
                    $result = $container->make(AuthorizationService::class);
                    // Если контейнер вернул Closure, вызываем его
                    if ($result instanceof \Closure) {
                        $instance = $result();
                    } else {
                        $instance = $result;
                    }
                } else {
                    // Если нет в контейнере, создаем напрямую
                    $roleRepoResult = $container->has(AdminRoleRepositoryInterface::class)
                        ? $container->make(AdminRoleRepositoryInterface::class)
                        : null;

                    // Обрабатываем Closure для roleRepo
                    $roleRepo = null;
                    if ($roleRepoResult instanceof \Closure) {
                        $roleRepo = $roleRepoResult();
                    } elseif ($roleRepoResult !== null) {
                        $roleRepo = $roleRepoResult;
                    } else {
                        $roleRepo = new AdminRoleRepository();
                    }
                    /** @phpstan-ignore-next-line */
                    $instance = new AuthorizationService($roleRepo);
                }
            } else {
                /** @phpstan-ignore-next-line */
                $instance = new AuthorizationService(new AdminRoleRepository());
            }

            $resolving = false;

            return $instance;
        } catch (\Throwable $e) {
            $resolving = false;
            // Не логируем ошибки циклической зависимости, чтобы не засорять логи
            if (strpos($e->getMessage(), 'Circular dependency') === false) {
                if (class_exists(Log::class)) {
                    Log::error('adminAuthorizationService error', ['error' => $e->getMessage(), 'exception' => $e]);
                }
            }

            return null;
        }
    }
}

/**
 * Получение экземпляра RoleManager через фасад
 */
if (!function_exists('roleManager')) {
    function roleManager(): RoleManager
    {
        if (class_exists(Role::class)) {
            return Role::manager();
        }

        return RoleManager::getInstance();
    }
}

/**
 * Проверка разрешения у пользователя
 */
if (!function_exists('user_can')) {
    function user_can(int $userId, string $permission): bool
    {
        $service = adminAuthorizationService();
        if ($service) {
            return $service->userHasPermission($userId, $permission);
        }

        return roleManager()->hasPermission($userId, $permission);
    }
}

/**
 * Проверка роли у пользователя
 */
if (!function_exists('user_has_role')) {
    function user_has_role(int $userId, string $roleSlug): bool
    {
        $service = adminAuthorizationService();
        if ($service) {
            return $service->userHasRole($userId, $roleSlug);
        }

        return roleManager()->hasRole($userId, $roleSlug);
    }
}

/**
 * Проверка разрешения у текущего пользователя (для админки)
 */
if (!function_exists('current_user_can')) {
    function current_user_can(string $permission): bool
    {
        // Сначала проверяем напрямую $_SESSION - это самый надежный способ
        $userId = null;
        if (session_status() === PHP_SESSION_ACTIVE && isset($_SESSION['admin_user_id'])) {
            $userId = (int)$_SESSION['admin_user_id'];
        }

        // Если не получили из $_SESSION, пробуем через Session::manager()
        if ($userId === null && class_exists(Session::class)) {
            $session = Session::manager();
            if ($session !== null) {
                $sessionUserId = $session->get('admin_user_id');
                if ($sessionUserId !== null && $sessionUserId !== false) {
                    $userId = (int)$sessionUserId;
                }
            }
        }

        // Если userId все еще null, возвращаем false
        if ($userId === null) {
            return false;
        }

        // Root пользователь (userId = 0) всегда имеет все права
        if ($userId === 0) {
            return true;
        }

        return user_can($userId, $permission);
    }
}

/**
 * Получение ID текущего авторизованного пользователя (для публичной части)
 */
if (!function_exists('auth_get_current_user_id')) {
    function auth_get_current_user_id(): ?int
    {
        if (!class_exists(Session::class)) {
            return null;
        }

        $session = Session::manager();
        if ($session === null) {
            return null;
        }
        $userId = $session->get('user_id');
        if (!$userId) {
            return null;
        }

        return (int)$userId;
    }
}

/**
 * Проверка разрешения у текущего авторизованного пользователя (для публичной части)
 */
if (!function_exists('auth_user_can')) {
    function auth_user_can(string $permission): bool
    {
        $userId = auth_get_current_user_id();
        if (!$userId) {
            return false;
        }

        return user_can($userId, $permission);
    }
}

/**
 * Получение всех разрешений пользователя
 */
if (!function_exists('user_permissions')) {
    function user_permissions(int $userId): array
    {
        $service = adminAuthorizationService();
        if ($service) {
            return $service->getUserPermissions($userId);
        }

        return roleManager()->getUserPermissions($userId);
    }
}

/**
 * Получение всех ролей пользователя
 */
if (!function_exists('user_roles')) {
    function user_roles(int $userId): array
    {
        $service = adminAuthorizationService();
        if ($service) {
            return $service->getUserRoles($userId);
        }

        return roleManager()->getUserRoles($userId);
    }
}

/**
 * Назначение роли пользователю
 */
if (!function_exists('assign_role')) {
    function assign_role(int $userId, int $roleId): bool
    {
        $service = adminAuthorizationService();
        if ($service) {
            return $service->assignRole($userId, $roleId);
        }

        return roleManager()->assignRole($userId, $roleId);
    }
}

/**
 * Удаление роли у пользователя
 */
if (!function_exists('remove_role')) {
    function remove_role(int $userId, int $roleId): bool
    {
        $service = adminAuthorizationService();
        if ($service) {
            return $service->removeRole($userId, $roleId);
        }

        return roleManager()->removeRole($userId, $roleId);
    }
}
