"""
Compatibility layer for gradual transition from legacy to granular permissions
"""
from django.conf import settings
from django.core.cache import cache
from django.utils import timezone
from typing import Dict, List, Optional, Any, Tuple
import logging

logger = logging.getLogger(__name__)


class PermissionCompatibilityLayer:
    """
    Compatibility layer that provides seamless transition between legacy and granular permission systems
    """
    
    def __init__(self):
        self.use_granular = getattr(settings, 'USE_GRANULAR_PERMISSIONS', False)
        self.fallback_to_legacy = getattr(settings, 'FALLBACK_TO_LEGACY_PERMISSIONS', True)
        self.cache_timeout = getattr(settings, 'PERMISSION_CACHE_TIMEOUT', 300)  # 5 minutes
    
    def has_permission(self, user, module: str, action: str) -> bool:
        """
        Check if user has permission using the appropriate system
        
        Args:
            user: CustomUser instance
            module: Module name (e.g., 'loans', 'clients')
            action: Action name (e.g., 'create', 'edit')
            
        Returns:
            bool: True if user has permission, False otherwise
        """
        # Try granular system first if enabled
        if self.use_granular:
            try:
                return self._check_granular_permission(user, module, action)
            except Exception as e:
                logger.warning(f"Granular permission check failed: {e}")
                if not self.fallback_to_legacy:
                    return False
        
        # Fall back to legacy system
        return self._check_legacy_permission(user, module, action)
    
    def has_page_permission(self, user, page_name: str, action_code: str) -> bool:
        """
        Check if user has page-specific permission
        
        Args:
            user: CustomUser instance
            page_name: Page name (e.g., 'loans', 'clients')
            action_code: Action code (e.g., 'loans_create_application')
            
        Returns:
            bool: True if user has permission, False otherwise
        """
        if self.use_granular:
            try:
                return self._check_granular_page_permission(user, page_name, action_code)
            except Exception as e:
                logger.warning(f"Granular page permission check failed: {e}")
                if not self.fallback_to_legacy:
                    return False
        
        # Convert to legacy format and check
        module, action = self._convert_page_permission_to_legacy(page_name, action_code)
        return self._check_legacy_permission(user, module, action)
    
    def get_user_permissions(self, user) -> Dict[str, Any]:
        """
        Get all permissions for a user in a unified format
        
        Args:
            user: CustomUser instance
            
        Returns:
            Dict containing permission information with source tracking
        """
        cache_key = f"user_permissions_{user.id}_{self.use_granular}"
        cached_permissions = cache.get(cache_key)
        
        if cached_permissions:
            return cached_permissions
        
        permissions = {}
        
        if self.use_granular:
            try:
                permissions = self._get_granular_permissions(user)
                permissions['system'] = 'granular'
            except Exception as e:
                logger.warning(f"Failed to get granular permissions: {e}")
                if self.fallback_to_legacy:
                    permissions = self._get_legacy_permissions(user)
                    permissions['system'] = 'legacy_fallback'
                else:
                    permissions = {'system': 'granular_failed', 'permissions': {}}
        else:
            permissions = self._get_legacy_permissions(user)
            permissions['system'] = 'legacy'
        
        # Cache the result
        cache.set(cache_key, permissions, self.cache_timeout)
        
        return permissions
    
    def get_available_actions(self, user, page_name: str) -> List[str]:
        """
        Get list of actions user can perform on a specific page
        
        Args:
            user: CustomUser instance
            page_name: Page name (e.g., 'loans', 'clients')
            
        Returns:
            List of action codes user can perform
        """
        if self.use_granular:
            try:
                return self._get_granular_available_actions(user, page_name)
            except Exception as e:
                logger.warning(f"Failed to get granular available actions: {e}")
                if not self.fallback_to_legacy:
                    return []
        
        # Fall back to legacy system
        return self._get_legacy_available_actions(user, page_name)
    
    def invalidate_user_cache(self, user):
        """Invalidate cached permissions for a user"""
        cache_keys = [
            f"user_permissions_{user.id}_True",
            f"user_permissions_{user.id}_False",
            f"granular_permissions_{user.id}",
            f"legacy_permissions_{user.id}",
        ]
        
        for key in cache_keys:
            cache.delete(key)
    
    def _check_granular_permission(self, user, module: str, action: str) -> bool:
        """Check permission using granular system"""
        try:
            from users.enhanced_permissions_models import PagePermission
            from users.services import PagePermissionManager
            
            # Convert module/action to page permission format
            page_name = self._convert_module_to_page(module)
            action_code = f"{module}_{action}"
            
            # Check if page permission exists
            try:
                page_permission = PagePermission.objects.get(
                    page_name=page_name,
                    action_code=action_code
                )
            except PagePermission.DoesNotExist:
                # If permission doesn't exist in granular system, fall back
                if self.fallback_to_legacy:
                    return self._check_legacy_permission(user, module, action)
                return False
            
            # Use PagePermissionManager to check permission
            permission_manager = PagePermissionManager()
            return permission_manager.check_action_permission(user, page_name, action_code)
            
        except ImportError:
            # Granular system not available
            if self.fallback_to_legacy:
                return self._check_legacy_permission(user, module, action)
            return False
    
    def _check_granular_page_permission(self, user, page_name: str, action_code: str) -> bool:
        """Check page permission using granular system"""
        try:
            from users.services import PagePermissionManager
            
            permission_manager = PagePermissionManager()
            return permission_manager.check_action_permission(user, page_name, action_code)
            
        except ImportError:
            # Convert to legacy format and check
            module, action = self._convert_page_permission_to_legacy(page_name, action_code)
            return self._check_legacy_permission(user, module, action)
    
    def _check_legacy_permission(self, user, module: str, action: str) -> bool:
        """Check permission using legacy system"""
        return user.has_permission(module, action)
    
    def _get_granular_permissions(self, user) -> Dict[str, Any]:
        """Get permissions using granular system"""
        try:
            from users.services import PagePermissionManager
            
            permission_manager = PagePermissionManager()
            
            # Get all page permissions for user
            permissions = {}
            
            # Get all available pages
            from users.enhanced_permissions_models import PagePermission
            pages = PagePermission.objects.values_list('page_name', flat=True).distinct()
            
            for page_name in pages:
                page_permissions = permission_manager.get_page_permissions(user, page_name)
                permissions[page_name] = page_permissions
            
            return {
                'permissions': permissions,
                'source': 'granular',
                'timestamp': timezone.now().isoformat()
            }
            
        except ImportError:
            raise Exception("Granular permission system not available")
    
    def _get_legacy_permissions(self, user) -> Dict[str, Any]:
        """Get permissions using legacy system"""
        permissions = user.get_effective_permissions()
        
        return {
            'permissions': permissions,
            'source': 'legacy',
            'timestamp': timezone.now().isoformat()
        }
    
    def _get_granular_available_actions(self, user, page_name: str) -> List[str]:
        """Get available actions using granular system"""
        try:
            from users.services import PagePermissionManager
            
            permission_manager = PagePermissionManager()
            return permission_manager.get_available_actions(user, page_name)
            
        except ImportError:
            return []
    
    def _get_legacy_available_actions(self, user, page_name: str) -> List[str]:
        """Get available actions using legacy system"""
        # Convert page name to modules and get available actions
        modules = self._get_modules_for_page(page_name)
        available_actions = []
        
        from users.models import RolePermission
        
        for module in modules:
            # Get all possible actions for this module
            actions = RolePermission.objects.filter(
                module=module
            ).values_list('action', flat=True).distinct()
            
            for action in actions:
                if user.has_permission(module, action):
                    available_actions.append(f"{module}_{action}")
        
        return available_actions
    
    def _convert_module_to_page(self, module: str) -> str:
        """Convert legacy module name to page name"""
        page_mapping = {
            'dashboard': 'dashboard',
            'dashboard_overview': 'dashboard',
            'dashboard_metrics': 'dashboard',
            'dashboard_charts': 'dashboard',
            'dashboard_recent_activities': 'dashboard',
            'dashboard_quick_actions': 'dashboard',
            'dashboard_loan_summary': 'dashboard',
            'dashboard_collection_summary': 'dashboard',
            'dashboard_branch_performance': 'dashboard',
            'dashboard_alerts': 'dashboard',
            
            'clients': 'clients',
            'clients_view_list': 'clients',
            'clients_search_filter': 'clients',
            'clients_create_new': 'clients',
            'clients_edit_profile': 'clients',
            'clients_delete_client': 'clients',
            'clients_view_details': 'clients',
            'clients_loan_history': 'clients',
            'clients_payment_history': 'clients',
            'clients_kyc_documents': 'clients',
            'clients_assign_portfolio': 'clients',
            'clients_registration_fee': 'clients',
            'clients_status_change': 'clients',
            'clients_export_data': 'clients',
            'clients_bulk_actions': 'clients',
            
            'loans': 'loans',
            'loans_view_list': 'loans',
            'loans_search_filter': 'loans',
            'loans_create_application': 'loans',
            'loans_edit_application': 'loans',
            'loans_delete_loan': 'loans',
            'loans_approve_application': 'loans',
            'loans_reject_application': 'loans',
            'loans_disburse_funds': 'loans',
            'loans_view_details': 'loans',
            'loans_amortization_schedule': 'loans',
            'loans_rollover_loan': 'loans',
            'loans_calculate_interest': 'loans',
            'loans_generate_receipt': 'loans',
            'loans_modify_terms': 'loans',
            'loans_close_loan': 'loans',
            'loans_export_data': 'loans',
            
            'repayments': 'repayments',
            'portfolio': 'portfolio',
            'reports_statements': 'reports',
            'documents': 'documents',
            'customer_documents': 'documents',
            'payment_receipts': 'receipts',
            'notifications': 'notifications',
            'settings': 'settings',
            'branch_settings': 'settings',
            'system_settings': 'settings',
        }
        
        return page_mapping.get(module, module.split('_')[0] if '_' in module else module)
    
    def _convert_page_permission_to_legacy(self, page_name: str, action_code: str) -> Tuple[str, str]:
        """Convert page permission to legacy module/action format"""
        # Extract module and action from action_code
        if '_' in action_code:
            parts = action_code.split('_', 1)
            module = parts[0]
            action = parts[1] if len(parts) > 1 else 'access'
        else:
            module = page_name
            action = action_code
        
        return module, action
    
    def _get_modules_for_page(self, page_name: str) -> List[str]:
        """Get legacy modules that correspond to a page"""
        page_to_modules = {
            'dashboard': [
                'dashboard', 'dashboard_overview', 'dashboard_metrics', 
                'dashboard_charts', 'dashboard_recent_activities', 'dashboard_quick_actions',
                'dashboard_loan_summary', 'dashboard_collection_summary', 
                'dashboard_branch_performance', 'dashboard_alerts'
            ],
            'clients': [
                'clients', 'clients_view_list', 'clients_search_filter',
                'clients_create_new', 'clients_edit_profile', 'clients_delete_client',
                'clients_view_details', 'clients_loan_history', 'clients_payment_history',
                'clients_kyc_documents', 'clients_assign_portfolio', 'clients_registration_fee',
                'clients_status_change', 'clients_export_data', 'clients_bulk_actions'
            ],
            'loans': [
                'loans', 'loans_view_list', 'loans_search_filter',
                'loans_create_application', 'loans_edit_application', 'loans_delete_loan',
                'loans_approve_application', 'loans_reject_application', 'loans_disburse_funds',
                'loans_view_details', 'loans_amortization_schedule', 'loans_rollover_loan',
                'loans_calculate_interest', 'loans_generate_receipt', 'loans_modify_terms',
                'loans_close_loan', 'loans_export_data'
            ],
            'repayments': ['repayments'],
            'portfolio': ['portfolio'],
            'reports': ['reports_statements'],
            'documents': ['documents', 'customer_documents'],
            'receipts': ['payment_receipts'],
            'notifications': ['notifications'],
            'settings': ['settings', 'branch_settings', 'system_settings'],
        }
        
        return page_to_modules.get(page_name, [page_name])


# Global instance for easy access
permission_compatibility = PermissionCompatibilityLayer()


def check_permission(user, module: str, action: str) -> bool:
    """
    Convenience function to check permissions using compatibility layer
    
    Args:
        user: CustomUser instance
        module: Module name
        action: Action name
        
    Returns:
        bool: True if user has permission
    """
    return permission_compatibility.has_permission(user, module, action)


def check_page_permission(user, page_name: str, action_code: str) -> bool:
    """
    Convenience function to check page permissions using compatibility layer
    
    Args:
        user: CustomUser instance
        page_name: Page name
        action_code: Action code
        
    Returns:
        bool: True if user has permission
    """
    return permission_compatibility.has_page_permission(user, page_name, action_code)


def get_user_permissions(user) -> Dict[str, Any]:
    """
    Convenience function to get user permissions using compatibility layer
    
    Args:
        user: CustomUser instance
        
    Returns:
        Dict containing permission information
    """
    return permission_compatibility.get_user_permissions(user)


def get_available_actions(user, page_name: str) -> List[str]:
    """
    Convenience function to get available actions using compatibility layer
    
    Args:
        user: CustomUser instance
        page_name: Page name
        
    Returns:
        List of available action codes
    """
    return permission_compatibility.get_available_actions(user, page_name)


def invalidate_user_permissions_cache(user):
    """
    Convenience function to invalidate user permissions cache
    
    Args:
        user: CustomUser instance
    """
    permission_compatibility.invalidate_user_cache(user)