"""
Core permission checking logic for role-based RBAC system
"""
from typing import Any, Optional, Union
from django.apps import apps
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
import logging

from ldc_dashboard_rbac.constants import (
    SettingsKeys, UserRoles, PermissionLevels, ErrorMessages, LogMessages
)

logger = logging.getLogger(__name__)


def get_rbac_config() -> dict:
    """Get RBAC configuration from Django settings"""
    config = getattr(settings, SettingsKeys.GROUP_RBAC, {})
    if not config:
        raise ImproperlyConfigured(ErrorMessages.GROUP_RBAC_MISSING)
    return config


def _get_model_with_validation(config_key: str, model_description: str):
    """Get a model from config with proper error handling"""
    config = get_rbac_config()
    model_path = config.get(config_key)
    
    if not model_path:
        example = config_key.split('_')[0].title()
        raise ImproperlyConfigured(
            ErrorMessages.REQUIRED_SETTING_MISSING.format(
                setting_key=config_key,
                description=model_description,
                example=example
            )
        )
    
    try:
        return apps.get_model(model_path)
    except Exception as e:
        raise ImproperlyConfigured(
            ErrorMessages.INVALID_MODEL_PATH.format(
                setting_key=config_key,
                model_path=model_path,
                error=e
            )
        )


def is_superadmin_user(user: Any) -> bool:
    """
    Check if user is superadmin
    
    Args:
        user: User instance (any model)
    
    Returns:
        bool: True if user is superadmin
    """
    if not user or getattr(user, 'is_anonymous', True):
        return False
    
    try:
        # Check if user has is_superadmin property (new system)
        if hasattr(user, 'is_superadmin'):
            return user.is_superadmin
        
        # Check role field (new system)
        if hasattr(user, 'role') and user.role == UserRoles.SUPERADMIN:
            return True
        
        # Fallback: check common superadmin attributes (legacy)
        if hasattr(user, 'is_superuser') and user.is_superuser:
            return True
        if hasattr(user, 'role') and user.role in UserRoles.SUPERADMIN_ROLES:
            return True
        if hasattr(user, 'user_type') and user.user_type in UserRoles.SUPERADMIN_ROLES:
            return True
            
        return False
        
    except Exception as e:
        logger.error(f"Error checking superadmin status for {user}: {e}")
        return False


def is_admin_user(user: Any) -> bool:
    """
    Check if user is admin (admin or superadmin)
    
    Args:
        user: User instance (any model)
    
    Returns:
        bool: True if user is admin or superadmin
    """
    if not user or getattr(user, 'is_anonymous', True):
        return False
    
    try:
        # Check if user has is_admin property (new system)
        if hasattr(user, 'is_admin'):
            return user.is_admin
        
        # Check role field (new system)
        if hasattr(user, 'role') and user.role in UserRoles.ADMIN_ROLES:
            return True
        
        # Fallback: check common admin attributes (legacy)
        if hasattr(user, 'is_staff') and user.is_staff:
            return True
        if hasattr(user, 'user_type') and user.user_type in UserRoles.ADMIN_ROLES:
            return True
            
        return False
        
    except Exception as e:
        logger.error(f"Error checking admin status for {user}: {e}")
        return False


def user_has_feature_permission(user: Any, feature_url_name: str, permission_level: str = PermissionLevels.READ) -> bool:
    """
    Check if user has permission for a feature with role-based access control
    
    Args:
        user: User instance (any model)
        feature_url_name: URL name of the feature
        permission_level: Required permission level
    
    Returns:
        bool: True if user has permission
    """
    if not user or getattr(user, 'is_anonymous', True):
        return False
    
    # ✅ SUPERADMIN BYPASS: Always allow superadmin access
    if is_superadmin_user(user):
        logger.info(LogMessages.SUPERADMIN_ACCESS_GRANTED.format(user=user, feature_name=feature_url_name))
        return True
    
    # ✅ ADMIN BYPASS: Always allow admin access
    if is_admin_user(user):
        logger.info(LogMessages.ADMIN_ACCESS_GRANTED.format(user=user, feature_name=feature_url_name))
        return True
    
    try:
        # Get models with proper validation
        feature_model = _get_model_with_validation(SettingsKeys.GroupRBAC.FEATURE_MODEL, 'Feature')
        user_group_model = _get_model_with_validation(SettingsKeys.GroupRBAC.USER_GROUP_MODEL, 'UserGroupMembership')
        permission_model = _get_model_with_validation(SettingsKeys.GroupRBAC.PERMISSION_MODEL, 'GroupFeaturePermission')
        
        # Check if feature exists and is active
        try:
            feature = feature_model.objects.get(url_name=feature_url_name, is_active=True)
        except feature_model.DoesNotExist:
            logger.warning(LogMessages.FEATURE_NOT_FOUND_WARNING.format(feature_name=feature_url_name))
            return False
        
        # Get user's active groups
        user_groups = user_group_model.objects.filter(
            user=user,
            is_active=True,
            group__is_active=True
        ).values_list('group_id', flat=True)
        
        if not user_groups:
            return False
        
        # Check feature-level permissions
        has_permission = permission_model.objects.filter(
            group_id__in=user_groups,
            feature=feature,
            is_enabled=True,
            permission_level__in=get_permission_hierarchy(permission_level)
        ).exists()
        
        return has_permission
        
    except Exception as e:
        logger.error(f"Error checking permission for {user} on {feature_url_name}: {e}")
        return False


def get_permission_hierarchy(level: str) -> list:
    """Get permission hierarchy (admin includes write and read)"""
    return PermissionLevels.HIERARCHY.get(level, PermissionLevels.HIERARCHY[PermissionLevels.READ])


def get_user_features(user: Any) -> list:
    """Get all features accessible to the user with role-based access"""
    if not user or getattr(user, 'is_anonymous', True):
        return []
    
    # ✅ SUPERADMIN BYPASS: Return all active features for superadmin
    if is_superadmin_user(user):
        try:
            feature_model = _get_model_with_validation(SettingsKeys.GroupRBAC.FEATURE_MODEL, 'Feature')
            return list(feature_model.objects.filter(is_active=True))
        except Exception as e:
            logger.error(f"Error getting all features for superadmin: {e}")
            return []
    
    # ✅ ADMIN BYPASS: Return all active features for admin
    if is_admin_user(user):
        try:
            feature_model = _get_model_with_validation(SettingsKeys.GroupRBAC.FEATURE_MODEL, 'Feature')
            return list(feature_model.objects.filter(is_active=True))
        except Exception as e:
            logger.error(f"Error getting all features for admin: {e}")
            return []
    
    try:
        feature_model = _get_model_with_validation(SettingsKeys.GroupRBAC.FEATURE_MODEL, 'Feature')
        user_group_model = _get_model_with_validation(SettingsKeys.GroupRBAC.USER_GROUP_MODEL, 'UserGroupMembership')
        permission_model = _get_model_with_validation(SettingsKeys.GroupRBAC.PERMISSION_MODEL, 'GroupFeaturePermission')
        
        # Get user's active groups
        user_groups = user_group_model.objects.filter(
            user=user,
            is_active=True,
            group__is_active=True
        ).values_list('group_id', flat=True)
        
        if not user_groups:
            return []
        
        # Get features with permissions (immediate database query)
        feature_ids = permission_model.objects.filter(
            group_id__in=user_groups,
            is_enabled=True,
            feature__is_active=True
        ).values_list('feature_id', flat=True).distinct()
        
        return list(feature_model.objects.filter(id__in=feature_ids))
        
    except Exception as e:
        logger.error(f"Error getting user features: {e}")
        return []


def get_models():
    """
    Get RBAC models dynamically based on configuration
    
    Returns:
        tuple: (User, Feature, Group, UserGroupMembership, GroupFeaturePermission, PasswordResetToken) models
    """
    try:
        # Get models with proper validation and consistent naming
        user_model = _get_model_with_validation(SettingsKeys.GroupRBAC.USER_MODEL, 'User')
        feature_model = _get_model_with_validation(SettingsKeys.GroupRBAC.FEATURE_MODEL, 'Feature')
        group_model = _get_model_with_validation(SettingsKeys.GroupRBAC.GROUP_MODEL, 'Group')
        user_group_model = _get_model_with_validation(SettingsKeys.GroupRBAC.USER_GROUP_MODEL, 'UserGroupMembership')
        permission_model = _get_model_with_validation(SettingsKeys.GroupRBAC.PERMISSION_MODEL, 'GroupFeaturePermission')
        password_reset_model = _get_model_with_validation(SettingsKeys.GroupRBAC.PASSWORD_RESET_MODEL, 'PasswordResetToken')
        
        return user_model, feature_model, group_model, user_group_model, permission_model, password_reset_model
        
    except Exception as e:
        logger.error(f"Error getting RBAC models: {e}")
        raise


def get_user_groups(user: Any):
    """
    Get all active groups for a user with role-based access
    
    Args:
        user: User instance (any model)
    
    Returns:
        QuerySet: Active groups for the user
    """
    if not user or getattr(user, 'is_anonymous', True):
        # Return empty queryset
        group_model = _get_model_with_validation(SettingsKeys.GroupRBAC.GROUP_MODEL, 'Group')
        return group_model.objects.none()
    
    # ✅ SUPERADMIN BYPASS: Return all active groups for superadmin
    if is_superadmin_user(user):
        try:
            group_model = _get_model_with_validation(SettingsKeys.GroupRBAC.GROUP_MODEL, 'Group')
            return group_model.objects.filter(is_active=True)
        except Exception as e:
            logger.error(f"Error getting all groups for superadmin: {e}")
            group_model = _get_model_with_validation(SettingsKeys.GroupRBAC.GROUP_MODEL, 'Group')
            return group_model.objects.none()
    
    # ✅ ADMIN BYPASS: Return all active groups for admin
    if is_admin_user(user):
        try:
            group_model = _get_model_with_validation(SettingsKeys.GroupRBAC.GROUP_MODEL, 'Group')
            return group_model.objects.filter(is_active=True)
        except Exception as e:
            logger.error(f"Error getting all groups for admin: {e}")
            group_model = _get_model_with_validation(SettingsKeys.GroupRBAC.GROUP_MODEL, 'Group')
            return group_model.objects.none()
    
    try:
        group_model = _get_model_with_validation(SettingsKeys.GroupRBAC.GROUP_MODEL, 'Group')
        user_group_model = _get_model_with_validation(SettingsKeys.GroupRBAC.USER_GROUP_MODEL, 'UserGroupMembership')
        
        # Get user's active groups
        group_ids = user_group_model.objects.filter(
            user=user,
            is_active=True,
            group__is_active=True
        ).values_list('group_id', flat=True)
        
        return group_model.objects.filter(id__in=group_ids)
        
    except Exception as e:
        logger.error(f"Error getting user groups: {e}")
        group_model = _get_model_with_validation(SettingsKeys.GroupRBAC.GROUP_MODEL, 'Group')
        return group_model.objects.none()


# Keep these functions for backward compatibility but make them no-ops
def clear_user_permissions_cache(user: Any):
    """No-op function for backward compatibility"""
    pass


def clear_all_rbac_cache():
    """No-op function for backward compatibility"""
    pass