"""
Test Configuration for Granular Permissions and Reporting System Tests

This module contains configuration settings and utilities for running tests.
"""

import os
from django.conf import settings
from django.test import override_settings


# Test database configuration
TEST_DATABASE_CONFIG = {
    'ENGINE': 'django.db.backends.sqlite3',
    'NAME': ':memory:',
    'OPTIONS': {
        'timeout': 20,
    }
}

# Test cache configuration
TEST_CACHE_CONFIG = {
    'default': {
        'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
        'LOCATION': 'test-cache',
    }
}

# Test email configuration
TEST_EMAIL_CONFIG = {
    'EMAIL_BACKEND': 'django.core.mail.backends.locmem.EmailBackend',
}

# Test media configuration
TEST_MEDIA_CONFIG = {
    'MEDIA_ROOT': '/tmp/test_media',
    'MEDIA_URL': '/test_media/',
}

# Test logging configuration
TEST_LOGGING_CONFIG = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console': {
            'class': 'logging.StreamHandler',
            'level': 'INFO',
        },
        'test_file': {
            'class': 'logging.FileHandler',
            'filename': '/tmp/test.log',
            'level': 'DEBUG',
        },
    },
    'loggers': {
        'users': {
            'handlers': ['console', 'test_file'],
            'level': 'DEBUG',
            'propagate': False,
        },
        'reports': {
            'handlers': ['console', 'test_file'],
            'level': 'DEBUG',
            'propagate': False,
        },
        'utils': {
            'handlers': ['console', 'test_file'],
            'level': 'DEBUG',
            'propagate': False,
        },
    },
}


class TestConfigMixin:
    """
    Mixin class for test configuration
    """
    
    @classmethod
    def setUpClass(cls):
        """Set up test class with configuration"""
        super().setUpClass()
        cls.setup_test_environment()
    
    @classmethod
    def setup_test_environment(cls):
        """Set up test environment"""
        # Ensure test directories exist
        os.makedirs('/tmp/test_media', exist_ok=True)
        os.makedirs('/tmp/test_exports', exist_ok=True)
        os.makedirs('/tmp/test_reports', exist_ok=True)
    
    def setUp(self):
        """Set up individual test"""
        super().setUp()
        self.setup_test_data()
    
    def setup_test_data(self):
        """Set up test data - to be overridden by subclasses"""
        pass
    
    def tearDown(self):
        """Clean up after test"""
        super().tearDown()
        self.cleanup_test_data()
    
    def cleanup_test_data(self):
        """Clean up test data - to be overridden by subclasses"""
        pass


# Test settings override decorator
test_settings = override_settings(
    DATABASES={'default': TEST_DATABASE_CONFIG},
    CACHES=TEST_CACHE_CONFIG,
    **TEST_EMAIL_CONFIG,
    **TEST_MEDIA_CONFIG,
    LOGGING=TEST_LOGGING_CONFIG,
    
    # Disable migrations for faster tests
    MIGRATION_MODULES={
        'users': None,
        'reports': None,
        'utils': None,
        'loans': None,
        'payments': None,
    },
    
    # Test-specific settings
    PASSWORD_HASHERS=[
        'django.contrib.auth.hashers.MD5PasswordHasher',  # Faster for tests
    ],
    
    # Disable debug toolbar in tests
    DEBUG_TOOLBAR_CONFIG={'SHOW_TOOLBAR_CALLBACK': lambda request: False},
    
    # Test celery configuration
    CELERY_TASK_ALWAYS_EAGER=True,
    CELERY_TASK_EAGER_PROPAGATES=True,
    
    # Test file storage
    DEFAULT_FILE_STORAGE='django.core.files.storage.FileSystemStorage',
    STATICFILES_STORAGE='django.contrib.staticfiles.storage.StaticFilesStorage',
)


# Test data factories
class TestDataFactory:
    """Factory for creating test data"""
    
    @staticmethod
    def create_test_branch(name="Test Branch", code="TB001"):
        """Create a test branch"""
        from users.models import Branch
        return Branch.objects.create(
            name=name,
            code=code,
            is_active=True
        )
    
    @staticmethod
    def create_test_user(username, role="loan_officer", branch=None):
        """Create a test user"""
        from django.contrib.auth import get_user_model
        User = get_user_model()
        
        if not branch:
            branch = TestDataFactory.create_test_branch()
        
        return User.objects.create_user(
            username=username,
            email=f"{username}@test.com",
            password="testpass123",
            role=role,
            branch=branch,
            phone_number=f"+254700{username[-6:]}"
        )
    
    @staticmethod
    def create_test_permission(page_name, action_code, category="view"):
        """Create a test page permission"""
        from users.enhanced_permissions_models import PagePermission
        return PagePermission.objects.create(
            page_name=page_name,
            action_code=action_code,
            action_name=action_code.replace('_', ' ').title(),
            description=f"Test permission for {action_code}",
            category=category
        )
    
    @staticmethod
    def create_test_role_template(role, permission, is_allowed=True):
        """Create a test role permission template"""
        from users.enhanced_permissions_models import RolePermissionTemplate
        return RolePermissionTemplate.objects.create(
            role=role,
            page_permission=permission,
            is_allowed=is_allowed
        )
    
    @staticmethod
    def create_test_portfolio_snapshot(manager, branch, **kwargs):
        """Create a test portfolio snapshot"""
        from users.enhanced_permissions_models import PortfolioSnapshot
        from django.utils import timezone
        from decimal import Decimal
        
        defaults = {
            'snapshot_date': timezone.now().date(),
            'total_clients': 10,
            'active_clients': 9,
            'active_loans': 8,
            'total_disbursed': Decimal('100000.00'),
            'total_outstanding': Decimal('60000.00'),
            'total_collected': Decimal('40000.00'),
            'collection_rate': Decimal('85.00'),
            'default_rate': Decimal('5.00')
        }
        defaults.update(kwargs)
        
        return PortfolioSnapshot.objects.create(
            manager=manager,
            branch=branch,
            **defaults
        )


# Test utilities
class TestUtils:
    """Utility functions for tests"""
    
    @staticmethod
    def assert_permission_structure(test_case, permissions):
        """Assert that permissions have the correct structure"""
        test_case.assertIsInstance(permissions, dict)
        for action, allowed in permissions.items():
            test_case.assertIsInstance(action, str)
            test_case.assertIsInstance(allowed, bool)
    
    @staticmethod
    def assert_export_result(test_case, result):
        """Assert that export result has the correct structure"""
        test_case.assertIn('success', result)
        test_case.assertIsInstance(result['success'], bool)
        
        if result['success']:
            test_case.assertIn('file_path', result)
            test_case.assertIn('rows_exported', result)
        else:
            test_case.assertIn('error', result)
    
    @staticmethod
    def assert_analytics_result(test_case, result):
        """Assert that analytics result has the correct structure"""
        test_case.assertIsInstance(result, dict)
        test_case.assertTrue(len(result) > 0)
    
    @staticmethod
    def create_mock_request(user=None, method='GET', data=None):
        """Create a mock request object"""
        from django.test import RequestFactory
        from django.contrib.auth.models import AnonymousUser
        
        factory = RequestFactory()
        
        if method.upper() == 'POST':
            request = factory.post('/', data or {})
        else:
            request = factory.get('/')
        
        request.user = user or AnonymousUser()
        return request
    
    @staticmethod
    def measure_execution_time(func, *args, **kwargs):
        """Measure execution time of a function"""
        import time
        start_time = time.time()
        result = func(*args, **kwargs)
        execution_time = time.time() - start_time
        return result, execution_time
    
    @staticmethod
    def generate_test_data(count, data_type='dict'):
        """Generate test data for performance testing"""
        if data_type == 'dict':
            return [
                {
                    'id': i,
                    'name': f'Test Item {i}',
                    'value': i * 100,
                    'active': i % 2 == 0
                }
                for i in range(count)
            ]
        elif data_type == 'users':
            return [
                {
                    'username': f'user{i}',
                    'email': f'user{i}@test.com',
                    'role': 'loan_officer' if i % 2 == 0 else 'secretary'
                }
                for i in range(count)
            ]
        else:
            return list(range(count))


# Test constants
class TestConstants:
    """Constants for testing"""
    
    # Test user roles
    ADMIN_ROLE = 'admin'
    TEAM_LEADER_ROLE = 'team_leader'
    LOAN_OFFICER_ROLE = 'loan_officer'
    SECRETARY_ROLE = 'secretary'
    AUDITOR_ROLE = 'auditor'
    
    # Test page names
    LOANS_PAGE = 'loans'
    CLIENTS_PAGE = 'clients'
    REPORTS_PAGE = 'reports'
    DASHBOARD_PAGE = 'dashboard'
    ADMIN_PAGE = 'admin'
    
    # Test permission categories
    VIEW_CATEGORY = 'view'
    CREATE_CATEGORY = 'create'
    EDIT_CATEGORY = 'edit'
    DELETE_CATEGORY = 'delete'
    APPROVE_CATEGORY = 'approve'
    EXPORT_CATEGORY = 'export'
    
    # Test file formats
    PDF_FORMAT = 'pdf'
    EXCEL_FORMAT = 'excel'
    CSV_FORMAT = 'csv'
    
    # Test performance thresholds
    MAX_PERMISSION_CHECK_TIME = 0.1  # seconds
    MAX_EXPORT_TIME_PER_1000_RECORDS = 5.0  # seconds
    MAX_ANALYTICS_CALCULATION_TIME = 2.0  # seconds
    
    # Test data sizes
    SMALL_DATASET_SIZE = 100
    MEDIUM_DATASET_SIZE = 1000
    LARGE_DATASET_SIZE = 10000


# Test decorators
def skip_if_no_database(test_func):
    """Skip test if database is not available"""
    import unittest
    from django.db import connection
    
    def wrapper(*args, **kwargs):
        try:
            connection.ensure_connection()
            return test_func(*args, **kwargs)
        except Exception:
            raise unittest.SkipTest("Database not available")
    
    return wrapper


def requires_cache(test_func):
    """Skip test if cache is not available"""
    import unittest
    from django.core.cache import cache
    
    def wrapper(*args, **kwargs):
        try:
            cache.set('test_key', 'test_value', 1)
            cache.get('test_key')
            return test_func(*args, **kwargs)
        except Exception:
            raise unittest.SkipTest("Cache not available")
    
    return wrapper


def performance_test(max_time=None):
    """Decorator to mark performance tests and set time limits"""
    def decorator(test_func):
        def wrapper(*args, **kwargs):
            import time
            start_time = time.time()
            result = test_func(*args, **kwargs)
            execution_time = time.time() - start_time
            
            if max_time and execution_time > max_time:
                raise AssertionError(
                    f"Performance test failed: {execution_time:.2f}s > {max_time}s"
                )
            
            return result
        
        wrapper._is_performance_test = True
        wrapper._max_time = max_time
        return wrapper
    
    return decorator