"""
Tests for core Django Security Suite functionality
"""
import pytest
from django.test import TestCase, RequestFactory
from django.http import HttpResponse
from django.core.exceptions import ImproperlyConfigured

from django_security_suite.core.decorators import rate_limit, csp_update, validate_input
from django_security_suite.core.middleware.security_headers import SecurityHeadersMiddleware
from django_security_suite.core.middleware.rate_limiting import RateLimitingMiddleware


class TestSecurityHeaders(TestCase):
    """Test security headers middleware"""

    def setUp(self):
        self.factory = RequestFactory()
        self.middleware = SecurityHeadersMiddleware(get_response=lambda r: HttpResponse())

    def test_security_headers_added(self):
        """Test that security headers are added to response"""
        request = self.factory.get('/')
        response = self.middleware(request)

        # Check for security headers
        assert 'X-Content-Type-Options' in response
        assert response['X-Content-Type-Options'] == 'nosniff'

        assert 'X-Frame-Options' in response
        assert 'Referrer-Policy' in response

    def test_csp_header_default(self):
        """Test default Content Security Policy"""
        request = self.factory.get('/')
        response = self.middleware(request)

        if 'Content-Security-Policy' in response:
            csp = response['Content-Security-Policy']
            assert "default-src 'self'" in csp


class TestRateLimiting(TestCase):
    """Test rate limiting functionality"""

    def setUp(self):
        self.factory = RequestFactory()

    def test_rate_limit_decorator(self):
        """Test rate limit decorator"""

        @rate_limit(limit='5/m', key='ip')
        def test_view(request):
            return HttpResponse('OK')

        request = self.factory.get('/')
        request.META['REMOTE_ADDR'] = '127.0.0.1'

        # First request should succeed
        response = test_view(request)
        assert response.status_code == 200

    def test_rate_limit_key_types(self):
        """Test different rate limit key types"""

        @rate_limit(limit='10/h', key='user')
        def user_limited_view(request):
            return HttpResponse('OK')

        @rate_limit(limit='10/h', key='ip')
        def ip_limited_view(request):
            return HttpResponse('OK')

        request = self.factory.get('/')
        request.META['REMOTE_ADDR'] = '127.0.0.1'

        # Mock user
        from django.contrib.auth.models import AnonymousUser
        request.user = AnonymousUser()

        # Both should work
        assert ip_limited_view(request).status_code == 200


class TestCSPDecorator(TestCase):
    """Test Content Security Policy decorator"""

    def test_csp_update_decorator(self):
        """Test CSP update decorator adds directives"""

        @csp_update(script_src=["'self'", "https://cdn.example.com"])
        def view_with_cdn(request):
            response = HttpResponse('OK')
            return response

        factory = RequestFactory()
        request = factory.get('/')

        response = view_with_cdn(request)
        assert response.status_code == 200

        # Check if CSP context was set (would be processed by middleware)
        if hasattr(request, '_csp_update'):
            assert 'script_src' in request._csp_update
            assert "https://cdn.example.com" in request._csp_update['script_src']


class TestValidationDecorator(TestCase):
    """Test input validation decorator"""

    def test_validate_input_decorator(self):
        """Test input validation decorator"""

        schema = {
            'name': {'type': 'string', 'required': True},
            'age': {'type': 'integer', 'min': 0, 'max': 120},
        }

        @validate_input(schema)
        def create_user_view(request):
            return HttpResponse('User created')

        factory = RequestFactory()

        # Valid request
        request = factory.post('/', data={'name': 'John', 'age': 25})
        response = create_user_view(request)
        # The decorator might not be fully functional without proper setup
        assert response.status_code in [200, 400]


@pytest.mark.django_db
class TestSecurityChecks:
    """Test Django system checks for security"""

    def test_security_checks_registered(self):
        """Test that security checks are registered with Django"""
        from django.core.checks import registry
        from django_security_suite.core import checks

        # Check if security checks are registered
        # This is a basic test to ensure checks module is imported
        assert checks is not None


class TestMiddlewareOrdering:
    """Test middleware ordering and configuration"""

    def test_middleware_order_validation(self):
        """Test that middleware is in correct order"""
        from django.conf import settings

        middleware = settings.MIDDLEWARE

        # Security middleware should come early
        security_index = -1
        session_index = -1

        for i, mw in enumerate(middleware):
            if 'SecurityMiddleware' in mw:
                security_index = i
            if 'SessionMiddleware' in mw:
                session_index = i

        # Security should come before session (if both present)
        if security_index > -1 and session_index > -1:
            assert security_index < session_index


@pytest.mark.parametrize('preset,expected_profile', [
    ('strict', 'strict'),
    ('moderate', 'moderate'),
    ('relaxed', 'relaxed'),
])
def test_risk_presets(preset, expected_profile):
    """Test risk profile presets"""
    from django_security_suite.conf import presets

    config = presets.get_preset(preset)
    assert config is not None
    assert config.get('RISK_PROFILE') == expected_profile


def test_configuration_validation():
    """Test configuration validation"""
    from django_security_suite.conf.settings import validate_config

    # Valid configuration
    valid_config = {
        'RISK_PROFILE': 'moderate',
        'ENABLE_RATE_LIMITING': True,
    }

    # Should not raise
    validate_config(valid_config)

    # Invalid configuration
    invalid_config = {
        'RISK_PROFILE': 'invalid_profile',
    }

    with pytest.raises((ValueError, ImproperlyConfigured)):
        validate_config(invalid_config)