from django.db import transaction
from user_roles.models import Role, UserRole
from django.contrib.auth import get_user_model

User = get_user_model()


class RoleService:
    """Сервис для управления ролями"""

    @staticmethod
    def create_default_roles():
        """
        Создает системные роли для тенанта.
        Вызывается при создании тенанта (автоматически через signals или admin).

        ВАЖНО: Эта функция вызывается в контексте schema_context(tenant.schema_name),
        поэтому роли создаются в schema конкретного тенанта автоматически!
        """
        default_roles = [
            {
                'code': Role.PLATFORM_SUPPORT,
                'name': 'Техподдержка платформы',
                'description': 'Служебный аккаунт техподдержки платформы. Полный доступ для помощи владельцу.',
                'is_system': True,
            },
            {
                'code': Role.OWNER,
                'name': 'Владелец',
                'description': 'Полный доступ ко всем функциям системы. Управление пользователями и настройками.',
                'is_system': True,
            },
            {
                'code': Role.MANAGER,
                'name': 'Менеджер',
                'description': 'Управление заказами, клиентами, товарами и складом. Без доступа к настройкам.',
                'is_system': True,
            },
            {
                'code': Role.FLORIST,
                'name': 'Флорист',
                'description': 'Работа с заказами и складскими операциями для заказов.',
                'is_system': True,
            },
            {
                'code': Role.COURIER,
                'name': 'Курьер',
                'description': 'Доставка заказов (права будут определены позже).',
                'is_system': True,
            },
        ]

        for role_data in default_roles:
            Role.objects.get_or_create(
                code=role_data['code'],
                defaults=role_data
            )

    @staticmethod
    def get_visible_roles():
        """
        Возвращает роли, видимые для пользователей тенанта.
        Исключает служебные роли (platform_support).
        """
        return Role.objects.exclude(code__in=Role.HIDDEN_ROLES)

    @staticmethod
    def get_visible_users():
        """
        Возвращает пользователей, видимых для владельца тенанта.
        Исключает пользователей с ролью platform_support.
        """
        from accounts.models import CustomUser
        hidden_user_ids = UserRole.objects.filter(
            role__code__in=Role.HIDDEN_ROLES
        ).values_list('user_id', flat=True)
        return CustomUser.objects.exclude(id__in=hidden_user_ids)

    @staticmethod
    def get_role_by_code(code):
        """Получить роль по коду"""
        try:
            return Role.objects.get(code=code, is_system=True)
        except Role.DoesNotExist:
            return None

    @staticmethod
    @transaction.atomic
    def assign_role_to_user(user, role_code, created_by=None):
        """
        Назначить роль пользователю в текущем тенанте.
        Если у пользователя уже есть роль - обновляет её.

        ВАЖНО: Вызывается в контексте текущего тенанта (через middleware),
        поэтому UserRole создается в schema текущего тенанта автоматически!
        """
        role = RoleService.get_role_by_code(role_code)
        if not role:
            raise ValueError(f"Роль с кодом '{role_code}' не найдена")

        user_role, created = UserRole.objects.update_or_create(
            user=user,
            defaults={
                'role': role,
                'created_by': created_by,
                'is_active': True,
            }
        )
        return user_role

    @staticmethod
    def get_user_role(user):
        """
        Получить роль пользователя в текущем тенанте.
        Оптимизация: использует уже загруженные данные если есть select_related.
        """
        try:
            # Проверяем, есть ли уже загруженная роль через select_related
            if hasattr(user, 'tenant_role'):
                # Проверяем, что tenant_role загружен (а не RelatedObjectDoesNotExist)
                try:
                    user_role = user.tenant_role
                    if user_role.is_active and hasattr(user_role, 'role'):
                        return user_role.role
                except UserRole.DoesNotExist:
                    pass
            
            # Если нет prefetch - делаем запрос
            user_role = UserRole.objects.get(user=user, is_active=True)
            return user_role.role
        except UserRole.DoesNotExist:
            return None

    @staticmethod
    def user_has_role(user, *role_codes):
        """Проверить, имеет ли пользователь одну из указанных ролей"""
        user_role = RoleService.get_user_role(user)
        if not user_role:
            return False
        return user_role.code in role_codes

    @staticmethod
    def can_modify_user_role(modifier_user, target_user_role):
        """
        Проверяет, может ли пользователь изменить указанную роль.

        Args:
            modifier_user: Пользователь, который хочет изменить роль
            target_user_role: UserRole объект, который нужно изменить

        Returns:
            tuple: (bool, str) - (можно ли изменить, причина отказа)
        """
        # Защита от самоблокировки
        if target_user_role.user == modifier_user:
            return False, "Вы не можете изменить свою собственную роль"

        # Можно добавить другие проверки в будущем:
        # - Запрет удаления последнего owner'а
        # - Проверка иерархии ролей и т.д.

        return True, ""
