#!/usr/bin/env python3
"""
Comprehensive Authentication Testing Suite for Adtlas Django Application

This script performs thorough testing of the authentication system including:
1. User Registration
2. Email Validation  
3. Login/Logout
4. Password Reset
5. Account Security Features
6. Role Management
7. Session Management

Author: Senior Django Developer
"""

import requests
import json
import time
import re
from urllib.parse import urljoin, urlparse, parse_qs
from datetime import datetime

class AdtlasAuthTester:
    def __init__(self, base_url="http://localhost:8002"):
        self.base_url = base_url
        self.session = requests.Session()
        self.test_results = []
        
    def log_test(self, test_name, passed, message=""):
        """Log test results"""
        status = "PASSED" if passed else "FAILED"
        timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        result = f"[{timestamp}] {test_name}: {status}"
        if message:
            result += f" - {message}"
        print(result)
        self.test_results.append({
            'test': test_name,
            'passed': passed,
            'message': message,
            'timestamp': timestamp
        })
        
    def get_csrf_token(self, url):
        """Extract CSRF token from form"""
        try:
            response = self.session.get(url)
            if response.status_code == 200:
                csrf_match = re.search(r'name="csrfmiddlewaretoken" value="([^"]+)"', response.text)
                if csrf_match:
                    return csrf_match.group(1)
        except Exception as e:
            print(f"Error getting CSRF token: {e}")
        return None
        
    def test_login_page_accessibility(self):
        """Test 1: Login page accessibility"""
        try:
            response = self.session.get(f"{self.base_url}/auth/login")
            passed = response.status_code == 200 and "login" in response.text.lower()
            self.log_test("Login Page Accessibility", passed, f"Status: {response.status_code}")
            return passed
        except Exception as e:
            self.log_test("Login Page Accessibility", False, str(e))
            return False
            
    def test_registration_page_accessibility(self):
        """Test 2: Registration page accessibility"""
        try:
            response = self.session.get(f"{self.base_url}/auth/register")
            passed = response.status_code == 200 and "register" in response.text.lower()
            self.log_test("Registration Page Accessibility", passed, f"Status: {response.status_code}")
            return passed
        except Exception as e:
            self.log_test("Registration Page Accessibility", False, str(e))
            return False
            
    def test_password_reset_page_accessibility(self):
        """Test 3: Password reset page accessibility"""
        try:
            response = self.session.get(f"{self.base_url}/auth/password-reset")
            passed = response.status_code == 200 and "password" in response.text.lower()
            self.log_test("Password Reset Page Accessibility", passed, f"Status: {response.status_code}")
            return passed
        except Exception as e:
            self.log_test("Password Reset Page Accessibility", False, str(e))
            return False
            
    def test_email_availability_api(self):
        """Test 4: Email availability API"""
        try:
            # Test with non-existing email
            response = self.session.get(f"{self.base_url}/auth/api/check-email?email=test_nonexisting@example.com")
            passed = response.status_code == 200
            if passed:
                data = response.json()
                passed = data.get('status') == 'success' and data.get('available') == True
            self.log_test("Email Availability API - Non-existing Email", passed, f"Response: {response.status_code}")
            
            # Test with empty email
            response = self.session.get(f"{self.base_url}/auth/api/check-email?email=")
            passed = response.status_code == 200
            if passed:
                data = response.json()
                passed = data.get('status') == 'error'
            self.log_test("Email Availability API - Empty Email", passed, f"Response: {response.status_code}")
            
            return passed
        except Exception as e:
            self.log_test("Email Availability API", False, str(e))
            return False
            
    def test_user_registration(self, email="testuser@adtlas.com", first_name="Test", last_name="User"):
        """Test 5: User registration process"""
        try:
            # Get registration page and CSRF token
            csrf_token = self.get_csrf_token(f"{self.base_url}/auth/register")
            if not csrf_token:
                self.log_test("User Registration", False, "Could not get CSRF token")
                return False
                
            # Prepare registration data
            registration_data = {
                'csrfmiddlewaretoken': csrf_token,
                'email': email,
                'first_name': first_name,
                'last_name': last_name,
                'password1': 'StrongPassword123!',
                'password2': 'StrongPassword123!',
                'phone_number': '+1234567890',
                'job_title': 'Software Engineer',
                'company': 'Test Company',
                'terms_accepted': 'on'
            }
            
            # Submit registration
            response = self.session.post(f"{self.base_url}/auth/register", data=registration_data)
            
            # Check if registration was successful (redirect to login or success message)
            passed = response.status_code in [200, 302]
            if response.status_code == 302:
                # Follow redirect to see if it goes to login page
                redirect_url = response.headers.get('Location', '')
                passed = 'login' in redirect_url
            elif response.status_code == 200:
                # Check for success indicators in response
                passed = 'success' in response.text.lower() or 'account created' in response.text.lower()
                
            self.log_test("User Registration", passed, f"Status: {response.status_code}")
            return passed
            
        except Exception as e:
            self.log_test("User Registration", False, str(e))
            return False
            
    def test_login_with_invalid_credentials(self):
        """Test 6: Login with invalid credentials"""
        try:
            csrf_token = self.get_csrf_token(f"{self.base_url}/auth/login")
            if not csrf_token:
                self.log_test("Login Invalid Credentials", False, "Could not get CSRF token")
                return False
                
            login_data = {
                'csrfmiddlewaretoken': csrf_token,
                'email': 'invalid@example.com',
                'password': 'wrongpassword'
            }
            
            response = self.session.post(f"{self.base_url}/auth/login", data=login_data)
            
            # Should return to login page with error message
            passed = response.status_code == 200 and 'invalid' in response.text.lower()
            self.log_test("Login Invalid Credentials", passed, "Should reject invalid credentials")
            return passed
            
        except Exception as e:
            self.log_test("Login Invalid Credentials", False, str(e))
            return False
            
    def test_password_reset_request(self):
        """Test 7: Password reset request"""
        try:
            csrf_token = self.get_csrf_token(f"{self.base_url}/auth/password-reset")
            if not csrf_token:
                self.log_test("Password Reset Request", False, "Could not get CSRF token")
                return False
                
            reset_data = {
                'csrfmiddlewaretoken': csrf_token,
                'email': 'testuser@adtlas.com'
            }
            
            response = self.session.post(f"{self.base_url}/auth/password-reset", data=reset_data)
            
            # Should show success message (regardless of email existence for security)
            passed = response.status_code in [200, 302]
            self.log_test("Password Reset Request", passed, f"Status: {response.status_code}")
            return passed
            
        except Exception as e:
            self.log_test("Password Reset Request", False, str(e))
            return False
            
    def test_form_validation(self):
        """Test 8: Form validation (weak password, mismatched passwords, etc.)"""
        try:
            csrf_token = self.get_csrf_token(f"{self.base_url}/auth/register")
            if not csrf_token:
                self.log_test("Form Validation", False, "Could not get CSRF token")
                return False
                
            # Test with weak password
            weak_password_data = {
                'csrfmiddlewaretoken': csrf_token,
                'email': 'weakpasstest@adtlas.com',
                'first_name': 'Test',
                'last_name': 'User',
                'password1': '123',
                'password2': '123',
                'terms_accepted': 'on'
            }
            
            response = self.session.post(f"{self.base_url}/auth/register", data=weak_password_data)
            passed = response.status_code == 200 and 'password' in response.text.lower()
            
            self.log_test("Form Validation - Weak Password", passed, "Should reject weak passwords")
            
            # Test with mismatched passwords
            mismatch_data = {
                'csrfmiddlewaretoken': csrf_token,
                'email': 'mismatchtest@adtlas.com',
                'first_name': 'Test',
                'last_name': 'User',
                'password1': 'StrongPassword123!',
                'password2': 'DifferentPassword123!',
                'terms_accepted': 'on'
            }
            
            response = self.session.post(f"{self.base_url}/auth/register", data=mismatch_data)
            passed = response.status_code == 200 and ('match' in response.text.lower() or 'password' in response.text.lower())
            
            self.log_test("Form Validation - Password Mismatch", passed, "Should reject mismatched passwords")
            return passed
            
        except Exception as e:
            self.log_test("Form Validation", False, str(e))
            return False
            
    def test_csrf_protection(self):
        """Test 9: CSRF protection"""
        try:
            # Try to submit form without CSRF token
            login_data = {
                'email': 'test@example.com',
                'password': 'password123'
            }
            
            response = self.session.post(f"{self.base_url}/auth/login", data=login_data)
            passed = response.status_code == 403 or 'csrf' in response.text.lower()
            
            self.log_test("CSRF Protection", passed, "Should require CSRF token")
            return passed
            
        except Exception as e:
            self.log_test("CSRF Protection", False, str(e))
            return False
            
    def run_all_tests(self):
        """Run all authentication tests"""
        print("=" * 60)
        print("ADTLAS AUTHENTICATION TESTING SUITE")
        print("=" * 60)
        
        tests = [
            self.test_login_page_accessibility,
            self.test_registration_page_accessibility,
            self.test_password_reset_page_accessibility,
            self.test_email_availability_api,
            self.test_user_registration,
            self.test_login_with_invalid_credentials,
            self.test_password_reset_request,
            self.test_form_validation,
            self.test_csrf_protection
        ]
        
        passed_tests = 0
        total_tests = len(tests)
        
        for test in tests:
            if test():
                passed_tests += 1
            time.sleep(0.5)  # Small delay between tests
            
        print("=" * 60)
        print(f"TESTING SUMMARY: {passed_tests}/{total_tests} tests passed")
        print(f"Success Rate: {(passed_tests/total_tests)*100:.1f}%")
        print("=" * 60)
        
        return self.test_results

if __name__ == "__main__":
    tester = AdtlasAuthTester()
    results = tester.run_all_tests()
