"""
Tests for Authentication Backend.

Test Coverage:
- Email-based authentication
- Password verification
- User retrieval
- Edge cases (wrong password, inactive user, etc.)
"""
import pytest
from django.contrib.auth import authenticate, get_user_model

User = get_user_model()


@pytest.mark.django_db
class TestEmailBackend:
    """Tests for the EmailBackend authentication."""

    def test_authenticate_with_valid_credentials(self, create_user):
        """Test authentication with valid email and password."""
        email = 'valid@example.com'
        password = 'validpass123'
        create_user(email=email, password=password)
        
        user = authenticate(username=email, password=password)
        
        assert user is not None
        assert user.email == email

    def test_authenticate_with_email_kwarg(self, create_user):
        """Test authentication using email keyword argument."""
        email = 'emailkwarg@example.com'
        password = 'testpass123'
        create_user(email=email, password=password)
        
        user = authenticate(email=email, password=password)
        
        assert user is not None
        assert user.email == email

    def test_authenticate_with_wrong_password(self, create_user):
        """Test authentication fails with wrong password."""
        email = 'wrongpass@example.com'
        create_user(email=email, password='correctpass123')
        
        user = authenticate(username=email, password='wrongpass123')
        
        assert user is None

    def test_authenticate_with_nonexistent_email(self):
        """Test authentication fails with non-existent email."""
        user = authenticate(
            username='nonexistent@example.com',
            password='testpass123'
        )
        
        assert user is None

    def test_authenticate_inactive_user(self, create_user):
        """Test authentication fails for inactive user."""
        email = 'inactiveauth@example.com'
        password = 'testpass123'
        create_user(email=email, password=password, is_active=False)
        
        user = authenticate(username=email, password=password)
        
        assert user is None

    def test_authenticate_with_empty_password(self, create_user):
        """Test authentication fails with empty password."""
        email = 'emptypass@example.com'
        create_user(email=email, password='testpass123')
        
        user = authenticate(username=email, password='')
        
        assert user is None

    def test_authenticate_with_none_password(self, create_user):
        """Test authentication fails with None password."""
        email = 'nonepass@example.com'
        create_user(email=email, password='testpass123')
        
        user = authenticate(username=email, password=None)
        
        assert user is None

    def test_authenticate_case_sensitive_email(self, create_user):
        """Test that email comparison handles case correctly."""
        email = 'CaseSensitive@example.com'
        password = 'testpass123'
        create_user(email=email, password=password)
        
        # Try with lowercase - should fail because email domain is normalized
        # but local part is case-sensitive
        user = authenticate(username='casesensitive@example.com', password=password)
        
        # Depending on implementation, this might or might not match
        # Our normalized email is stored as 'CaseSensitive@example.com'
        # so lowercase won't match
        assert user is None

    def test_timing_attack_protection(self):
        """Test that non-existent user check doesn't expose timing info."""
        # This test ensures the backend runs password hashing even for
        # non-existent users to prevent timing attacks
        import time
        
        # Authenticate with non-existent user
        start = time.time()
        authenticate(username='nonexistent1@example.com', password='testpass123')
        nonexistent_time = time.time() - start
        
        # The authentication should still take some time due to password hashing
        # This is a rough check - in production you'd use more sophisticated timing
        assert nonexistent_time > 0


@pytest.mark.django_db
class TestBackendGetUser:
    """Tests for the get_user method of EmailBackend."""

    def test_get_user_by_id(self, create_user):
        """Test retrieving user by ID."""
        from apps.core.auth.backends import EmailBackend
        
        user = create_user(email='getuser@example.com')
        backend = EmailBackend()
        
        retrieved_user = backend.get_user(user.id)
        
        assert retrieved_user is not None
        assert retrieved_user.id == user.id

    def test_get_user_nonexistent_id(self):
        """Test retrieving non-existent user returns None."""
        from apps.core.auth.backends import EmailBackend
        
        backend = EmailBackend()
        
        retrieved_user = backend.get_user(99999)
        
        assert retrieved_user is None
