# -*- coding: utf-8 -*-
"""
Authentification App Tests

This module contains comprehensive tests for the authentification app.
"""

from django.test import TestCase, Client
from django.urls import reverse
from django.contrib.auth import get_user_model
from django.utils import timezone
from datetime import timedelta
from rest_framework.test import APITestCase
from rest_framework import status
from .models import PasswordResetToken, LoginAttempt
from .serializers import LoginSerializer, PasswordResetRequestSerializer

User = get_user_model()


class PasswordResetTokenModelTest(TestCase):
    """
    Test cases for PasswordResetToken model.
    """
    
    def setUp(self):
        self.user = User.objects.create_user(
            username='testuser',
            email='test@example.com',
            password='testpass123'
        )
    
    def test_token_creation(self):
        """Test password reset token creation."""
        token = PasswordResetToken.objects.create(user=self.user)
        self.assertIsNotNone(token.token)
        self.assertIsNotNone(token.expires_at)
        self.assertTrue(token.is_valid())
    
    def test_token_expiration(self):
        """Test token expiration logic."""
        token = PasswordResetToken.objects.create(
            user=self.user,
            expires_at=timezone.now() - timedelta(hours=1)
        )
        self.assertFalse(token.is_valid())
    
    def test_token_usage(self):
        """Test token usage marking."""
        token = PasswordResetToken.objects.create(user=self.user)
        self.assertTrue(token.is_valid())
        
        token.mark_as_used()
        self.assertFalse(token.is_valid())
        self.assertIsNotNone(token.used_at)


class LoginAttemptModelTest(TestCase):
    """
    Test cases for LoginAttempt model.
    """
    
    def test_login_attempt_creation(self):
        """Test login attempt creation."""
        attempt = LoginAttempt.objects.create(
            username='testuser',
            ip_address='192.168.1.1',
            success=True
        )
        self.assertEqual(attempt.username, 'testuser')
        self.assertEqual(attempt.ip_address, '192.168.1.1')
        self.assertTrue(attempt.success)
    
    def test_failed_login_attempt(self):
        """Test failed login attempt with reason."""
        attempt = LoginAttempt.objects.create(
            username='testuser',
            ip_address='192.168.1.1',
            success=False,
            failure_reason='Invalid password'
        )
        self.assertFalse(attempt.success)
        self.assertEqual(attempt.failure_reason, 'Invalid password')


class LoginSerializerTest(TestCase):
    """
    Test cases for LoginSerializer.
    """
    
    def setUp(self):
        self.user = User.objects.create_user(
            username='testuser',
            email='test@example.com',
            password='testpass123'
        )
    
    def test_valid_login(self):
        """Test valid login serialization."""
        data = {
            'username': 'testuser',
            'password': 'testpass123'
        }
        serializer = LoginSerializer(data=data)
        self.assertTrue(serializer.is_valid())
        self.assertEqual(serializer.validated_data['user'], self.user)
    
    def test_invalid_credentials(self):
        """Test invalid credentials."""
        data = {
            'username': 'testuser',
            'password': 'wrongpassword'
        }
        serializer = LoginSerializer(data=data)
        self.assertFalse(serializer.is_valid())
        self.assertIn('Invalid credentials', str(serializer.errors))
    
    def test_inactive_user(self):
        """Test login with inactive user."""
        self.user.is_active = False
        self.user.save()
        
        data = {
            'username': 'testuser',
            'password': 'testpass123'
        }
        serializer = LoginSerializer(data=data)
        self.assertFalse(serializer.is_valid())
        self.assertIn('User account is disabled', str(serializer.errors))


class PasswordResetRequestSerializerTest(TestCase):
    """
    Test cases for PasswordResetRequestSerializer.
    """
    
    def setUp(self):
        self.user = User.objects.create_user(
            username='testuser',
            email='test@example.com',
            password='testpass123'
        )
    
    def test_valid_email(self):
        """Test valid email for password reset."""
        data = {'email': 'test@example.com'}
        serializer = PasswordResetRequestSerializer(data=data)
        self.assertTrue(serializer.is_valid())
    
    def test_invalid_email(self):
        """Test invalid email for password reset."""
        data = {'email': 'nonexistent@example.com'}
        serializer = PasswordResetRequestSerializer(data=data)
        self.assertFalse(serializer.is_valid())
        self.assertIn('No user found', str(serializer.errors))


class AuthenticationViewsTest(APITestCase):
    """
    Test cases for authentication views.
    """
    
    def setUp(self):
        self.user = User.objects.create_user(
            username='testuser',
            email='test@example.com',
            password='testpass123'
        )
        self.client = Client()
    
    def test_login_view(self):
        """Test login view functionality."""
        # This would test the actual login view when implemented
        pass
    
    def test_password_reset_view(self):
        """Test password reset view functionality."""
        # This would test the actual password reset view when implemented
        pass


class SecurityTest(TestCase):
    """
    Test cases for security features.
    """
    
    def setUp(self):
        self.user = User.objects.create_user(
            username='testuser',
            email='test@example.com',
            password='testpass123'
        )
    
    def test_login_attempt_logging(self):
        """Test that login attempts are logged."""
        # This would test login attempt logging when middleware is implemented
        pass
    
    def test_password_reset_token_uniqueness(self):
        """Test that password reset tokens are unique."""
        token1 = PasswordResetToken.objects.create(user=self.user)
        token2 = PasswordResetToken.objects.create(user=self.user)
        self.assertNotEqual(token1.token, token2.token)
    
    def test_multiple_password_reset_tokens(self):
        """Test that multiple tokens can exist for a user."""
        token1 = PasswordResetToken.objects.create(user=self.user)
        token2 = PasswordResetToken.objects.create(user=self.user)
        
        tokens = PasswordResetToken.objects.filter(user=self.user)
        self.assertEqual(tokens.count(), 2)