#!/usr/bin/env python3
"""
Backend API Testing for Solar Panel Company
Tests all API endpoints with comprehensive validation scenarios
"""

import requests
import json
import time
from datetime import datetime
from typing import Dict, Any

# Configuration
BASE_URL = "https://solar-install-2.preview.emergentagent.com/api"
TIMEOUT = 30

class BackendTester:
    def __init__(self):
        self.results = []
        self.session = requests.Session()
        self.session.timeout = TIMEOUT
        
    def log_result(self, test_name: str, success: bool, details: str, response_data: Any = None):
        """Log test result"""
        result = {
            "test": test_name,
            "success": success,
            "details": details,
            "timestamp": datetime.now().isoformat(),
            "response_data": response_data
        }
        self.results.append(result)
        status = "✅ PASS" if success else "❌ FAIL"
        print(f"{status} {test_name}: {details}")
        
    def test_api_health(self):
        """Test basic API connectivity"""
        try:
            response = self.session.get(f"{BASE_URL}/")
            if response.status_code == 200:
                data = response.json()
                if "Solaire France Pro API" in data.get("message", ""):
                    self.log_result("API Health Check", True, "API is operational", data)
                    return True
                else:
                    self.log_result("API Health Check", False, f"Unexpected response: {data}")
            else:
                self.log_result("API Health Check", False, f"HTTP {response.status_code}: {response.text}")
        except Exception as e:
            self.log_result("API Health Check", False, f"Connection error: {str(e)}")
        return False

    def test_contact_form_valid_submission(self):
        """Test valid contact form submission"""
        valid_data = {
            "firstName": "Jean-Pierre",
            "lastName": "Dubois",
            "email": "jean-pierre.dubois@email.fr",
            "phone": "0123456789",
            "postalCode": "75001",
            "housingType": "maison",
            "message": "Je souhaite obtenir un devis pour l'installation de panneaux solaires sur ma maison.",
            "gdprConsent": True
        }
        
        try:
            response = self.session.post(f"{BASE_URL}/contact", json=valid_data)
            if response.status_code == 200:
                data = response.json()
                if data.get("success") and "succès" in data.get("message", ""):
                    self.log_result("Contact Form Valid Submission", True, "Successfully submitted contact form", data)
                    return data.get("data", {}).get("id")
                else:
                    self.log_result("Contact Form Valid Submission", False, f"Invalid response format: {data}")
            else:
                self.log_result("Contact Form Valid Submission", False, f"HTTP {response.status_code}: {response.text}")
        except Exception as e:
            self.log_result("Contact Form Valid Submission", False, f"Request error: {str(e)}")
        return None

    def test_contact_form_phone_validation(self):
        """Test French phone number validation"""
        test_cases = [
            ("0123456789", True, "Valid 10-digit phone"),
            ("01 23 45 67 89", True, "Valid phone with spaces"),
            ("01.23.45.67.89", True, "Valid phone with dots"),
            ("0623456789", True, "Valid mobile phone"),
            ("123456789", False, "Missing leading zero"),
            ("0023456789", False, "Invalid area code"),
            ("012345678", False, "Too short"),
            ("01234567890", False, "Too long"),
            ("abcdefghij", False, "Non-numeric characters")
        ]
        
        base_data = {
            "firstName": "Marie",
            "lastName": "Martin",
            "email": "marie.martin@email.fr",
            "postalCode": "69000",
            "housingType": "appartement",
            "gdprConsent": True
        }
        
        for phone, should_pass, description in test_cases:
            test_data = {**base_data, "phone": phone}
            try:
                response = self.session.post(f"{BASE_URL}/contact", json=test_data)
                if should_pass:
                    if response.status_code == 200:
                        self.log_result(f"Phone Validation - {description}", True, f"Accepted valid phone: {phone}")
                    else:
                        self.log_result(f"Phone Validation - {description}", False, f"Rejected valid phone: {phone} - {response.text}")
                else:
                    if response.status_code in [400, 422]:
                        self.log_result(f"Phone Validation - {description}", True, f"Correctly rejected invalid phone: {phone}")
                    else:
                        self.log_result(f"Phone Validation - {description}", False, f"Should have rejected invalid phone: {phone}")
            except Exception as e:
                self.log_result(f"Phone Validation - {description}", False, f"Request error: {str(e)}")

    def test_contact_form_postal_code_validation(self):
        """Test postal code validation"""
        test_cases = [
            ("75001", True, "Valid Paris postal code"),
            ("69000", True, "Valid Lyon postal code"),
            ("13000", True, "Valid Marseille postal code"),
            ("1234", False, "Too short"),
            ("123456", False, "Too long"),
            ("abcde", False, "Non-numeric"),
            ("7500a", False, "Mixed characters")
        ]
        
        base_data = {
            "firstName": "François",
            "lastName": "Leroy",
            "email": "francois.leroy@email.fr",
            "phone": "0145678901",
            "housingType": "ferme",
            "gdprConsent": True
        }
        
        for postal_code, should_pass, description in test_cases:
            test_data = {**base_data, "postalCode": postal_code}
            try:
                response = self.session.post(f"{BASE_URL}/contact", json=test_data)
                if should_pass:
                    if response.status_code == 200:
                        self.log_result(f"Postal Code Validation - {description}", True, f"Accepted valid code: {postal_code}")
                    else:
                        self.log_result(f"Postal Code Validation - {description}", False, f"Rejected valid code: {postal_code}")
                else:
                    if response.status_code in [400, 422]:
                        self.log_result(f"Postal Code Validation - {description}", True, f"Correctly rejected invalid code: {postal_code}")
                    else:
                        self.log_result(f"Postal Code Validation - {description}", False, f"Should have rejected invalid code: {postal_code}")
            except Exception as e:
                self.log_result(f"Postal Code Validation - {description}", False, f"Request error: {str(e)}")

    def test_contact_form_required_fields(self):
        """Test required field validation"""
        complete_data = {
            "firstName": "Claire",
            "lastName": "Moreau",
            "email": "claire.moreau@email.fr",
            "phone": "0156789012",
            "postalCode": "13000",
            "housingType": "local",
            "gdprConsent": True
        }
        
        required_fields = ["firstName", "lastName", "email", "phone", "postalCode", "housingType", "gdprConsent"]
        
        for field in required_fields:
            test_data = complete_data.copy()
            del test_data[field]
            
            try:
                response = self.session.post(f"{BASE_URL}/contact", json=test_data)
                if response.status_code == 422 or response.status_code == 400:
                    self.log_result(f"Required Field - {field}", True, f"Correctly rejected missing {field}")
                else:
                    self.log_result(f"Required Field - {field}", False, f"Should have rejected missing {field}")
            except Exception as e:
                self.log_result(f"Required Field - {field}", False, f"Request error: {str(e)}")

    def test_contact_form_gdpr_consent(self):
        """Test GDPR consent requirement"""
        base_data = {
            "firstName": "Pierre",
            "lastName": "Bernard",
            "email": "pierre.bernard@email.fr",
            "phone": "0167890123",
            "postalCode": "75001",
            "housingType": "maison"
        }
        
        # Test with gdprConsent = false
        test_data = {**base_data, "gdprConsent": False}
        try:
            response = self.session.post(f"{BASE_URL}/contact", json=test_data)
            if response.status_code in [400, 422]:
                self.log_result("GDPR Consent False", True, "Correctly rejected gdprConsent=false")
            else:
                self.log_result("GDPR Consent False", False, "Should have rejected gdprConsent=false")
        except Exception as e:
            self.log_result("GDPR Consent False", False, f"Request error: {str(e)}")

    def test_contact_form_housing_type_validation(self):
        """Test housing type enum validation"""
        valid_types = ["maison", "appartement", "ferme", "local"]
        invalid_types = ["villa", "château", "bureau", ""]
        
        base_data = {
            "firstName": "Sophie",
            "lastName": "Petit",
            "email": "sophie.petit@email.fr",
            "phone": "0178901234",
            "postalCode": "69000",
            "gdprConsent": True
        }
        
        # Test valid housing types
        for housing_type in valid_types:
            test_data = {**base_data, "housingType": housing_type}
            try:
                response = self.session.post(f"{BASE_URL}/contact", json=test_data)
                if response.status_code == 200:
                    self.log_result(f"Housing Type Valid - {housing_type}", True, f"Accepted valid type: {housing_type}")
                else:
                    self.log_result(f"Housing Type Valid - {housing_type}", False, f"Rejected valid type: {housing_type}")
            except Exception as e:
                self.log_result(f"Housing Type Valid - {housing_type}", False, f"Request error: {str(e)}")
        
        # Test invalid housing types
        for housing_type in invalid_types:
            test_data = {**base_data, "housingType": housing_type}
            try:
                response = self.session.post(f"{BASE_URL}/contact", json=test_data)
                if response.status_code == 400 or response.status_code == 422:
                    self.log_result(f"Housing Type Invalid - {housing_type}", True, f"Correctly rejected invalid type: {housing_type}")
                else:
                    self.log_result(f"Housing Type Invalid - {housing_type}", False, f"Should have rejected invalid type: {housing_type}")
            except Exception as e:
                self.log_result(f"Housing Type Invalid - {housing_type}", False, f"Request error: {str(e)}")

    def test_contact_form_name_validation(self):
        """Test French name validation"""
        valid_names = ["Jean-Pierre", "Marie-Claire", "François", "Élise", "O'Connor"]
        invalid_names = ["Jean123", "Marie@", "Test$", ""]
        
        base_data = {
            "lastName": "Dupont",
            "email": "test@email.fr",
            "phone": "0189012345",
            "postalCode": "75001",
            "housingType": "maison",
            "gdprConsent": True
        }
        
        # Test valid first names
        for name in valid_names:
            test_data = {**base_data, "firstName": name}
            try:
                response = self.session.post(f"{BASE_URL}/contact", json=test_data)
                if response.status_code == 200:
                    self.log_result(f"Name Valid - {name}", True, f"Accepted valid name: {name}")
                else:
                    self.log_result(f"Name Valid - {name}", False, f"Rejected valid name: {name}")
            except Exception as e:
                self.log_result(f"Name Valid - {name}", False, f"Request error: {str(e)}")
        
        # Test invalid first names
        for name in invalid_names:
            if name:  # Skip empty string as it's handled by required field validation
                test_data = {**base_data, "firstName": name}
                try:
                    response = self.session.post(f"{BASE_URL}/contact", json=test_data)
                    if response.status_code in [400, 422]:
                        self.log_result(f"Name Invalid - {name}", True, f"Correctly rejected invalid name: {name}")
                    else:
                        self.log_result(f"Name Invalid - {name}", False, f"Should have rejected invalid name: {name}")
                except Exception as e:
                    self.log_result(f"Name Invalid - {name}", False, f"Request error: {str(e)}")

    def test_newsletter_valid_subscription(self):
        """Test valid newsletter subscription"""
        import uuid
        valid_email = f"newsletter.test.{str(uuid.uuid4())[:8]}@email.fr"
        
        try:
            response = self.session.post(f"{BASE_URL}/newsletter", json={"email": valid_email})
            if response.status_code == 200:
                data = response.json()
                if data.get("success") and ("abonnement" in data.get("message", "").lower() or "déjà abonné" in data.get("message", "").lower()):
                    self.log_result("Newsletter Valid Subscription", True, "Successfully handled newsletter subscription", data)
                    return True
                else:
                    self.log_result("Newsletter Valid Subscription", False, f"Invalid response format: {data}")
            else:
                self.log_result("Newsletter Valid Subscription", False, f"HTTP {response.status_code}: {response.text}")
        except Exception as e:
            self.log_result("Newsletter Valid Subscription", False, f"Request error: {str(e)}")
        return False

    def test_newsletter_duplicate_handling(self):
        """Test duplicate email handling"""
        import uuid
        duplicate_email = f"duplicate.test.{str(uuid.uuid4())[:8]}@email.fr"
        
        # First subscription
        try:
            response1 = self.session.post(f"{BASE_URL}/newsletter", json={"email": duplicate_email})
            if response1.status_code == 200:
                # Second subscription (duplicate)
                response2 = self.session.post(f"{BASE_URL}/newsletter", json={"email": duplicate_email})
                if response2.status_code == 200:
                    data = response2.json()
                    if "déjà abonné" in data.get("message", "").lower():
                        self.log_result("Newsletter Duplicate Handling", True, "Correctly handled duplicate subscription")
                    else:
                        self.log_result("Newsletter Duplicate Handling", True, "Handled duplicate gracefully")
                else:
                    self.log_result("Newsletter Duplicate Handling", False, f"Failed on duplicate: {response2.text}")
            else:
                self.log_result("Newsletter Duplicate Handling", False, f"Failed initial subscription: {response1.text}")
        except Exception as e:
            self.log_result("Newsletter Duplicate Handling", False, f"Request error: {str(e)}")

    def test_newsletter_email_validation(self):
        """Test newsletter email validation"""
        test_cases = [
            ("valid@email.fr", True, "Valid email"),
            ("user.name@domain.com", True, "Valid email with dot"),
            ("user+tag@domain.fr", True, "Valid email with plus"),
            ("invalid-email", False, "Missing @ symbol"),
            ("@domain.com", False, "Missing local part"),
            ("user@", False, "Missing domain"),
            ("", False, "Empty email")
        ]
        
        for email, should_pass, description in test_cases:
            try:
                response = self.session.post(f"{BASE_URL}/newsletter", json={"email": email})
                if should_pass:
                    if response.status_code == 200:
                        self.log_result(f"Newsletter Email - {description}", True, f"Accepted valid email: {email}")
                    else:
                        self.log_result(f"Newsletter Email - {description}", False, f"Rejected valid email: {email}")
                else:
                    if response.status_code == 400 or response.status_code == 422:
                        self.log_result(f"Newsletter Email - {description}", True, f"Correctly rejected invalid email: {email}")
                    else:
                        self.log_result(f"Newsletter Email - {description}", False, f"Should have rejected invalid email: {email}")
            except Exception as e:
                self.log_result(f"Newsletter Email - {description}", False, f"Request error: {str(e)}")

    def test_database_operations(self):
        """Test database read operations"""
        try:
            # Test GET /api/contact
            response = self.session.get(f"{BASE_URL}/contact")
            if response.status_code == 200:
                data = response.json()
                if isinstance(data, list):
                    self.log_result("Database - Contact GET", True, f"Retrieved {len(data)} contact submissions")
                else:
                    self.log_result("Database - Contact GET", False, "Response is not a list")
            else:
                self.log_result("Database - Contact GET", False, f"HTTP {response.status_code}: {response.text}")
        except Exception as e:
            self.log_result("Database - Contact GET", False, f"Request error: {str(e)}")
        
        try:
            # Test GET /api/newsletter
            response = self.session.get(f"{BASE_URL}/newsletter")
            if response.status_code == 200:
                data = response.json()
                if isinstance(data, list):
                    self.log_result("Database - Newsletter GET", True, f"Retrieved {len(data)} newsletter subscriptions")
                else:
                    self.log_result("Database - Newsletter GET", False, "Response is not a list")
            else:
                self.log_result("Database - Newsletter GET", False, f"HTTP {response.status_code}: {response.text}")
        except Exception as e:
            self.log_result("Database - Newsletter GET", False, f"Request error: {str(e)}")

    def test_error_handling(self):
        """Test API error handling"""
        # Test invalid JSON
        try:
            response = self.session.post(f"{BASE_URL}/contact", data="invalid json")
            if response.status_code == 400 or response.status_code == 422:
                self.log_result("Error Handling - Invalid JSON", True, "Correctly handled invalid JSON")
            else:
                self.log_result("Error Handling - Invalid JSON", False, f"Unexpected response to invalid JSON: {response.status_code}")
        except Exception as e:
            self.log_result("Error Handling - Invalid JSON", False, f"Request error: {str(e)}")
        
        # Test non-existent endpoint
        try:
            response = self.session.get(f"{BASE_URL}/nonexistent")
            if response.status_code == 404:
                self.log_result("Error Handling - 404", True, "Correctly returned 404 for non-existent endpoint")
            else:
                self.log_result("Error Handling - 404", False, f"Expected 404, got {response.status_code}")
        except Exception as e:
            self.log_result("Error Handling - 404", False, f"Request error: {str(e)}")

    def run_all_tests(self):
        """Run all backend tests"""
        print("🚀 Starting Backend API Tests for Solar Panel Company")
        print(f"📡 Testing API at: {BASE_URL}")
        print("=" * 60)
        
        # Basic connectivity
        if not self.test_api_health():
            print("❌ API is not accessible. Stopping tests.")
            return False
        
        print("\n📋 Testing Contact Form API...")
        self.test_contact_form_valid_submission()
        self.test_contact_form_phone_validation()
        self.test_contact_form_postal_code_validation()
        self.test_contact_form_required_fields()
        self.test_contact_form_gdpr_consent()
        self.test_contact_form_housing_type_validation()
        self.test_contact_form_name_validation()
        
        print("\n📧 Testing Newsletter API...")
        self.test_newsletter_valid_subscription()
        self.test_newsletter_duplicate_handling()
        self.test_newsletter_email_validation()
        
        print("\n🗄️ Testing Database Operations...")
        self.test_database_operations()
        
        print("\n⚠️ Testing Error Handling...")
        self.test_error_handling()
        
        return True

    def print_summary(self):
        """Print test summary"""
        total_tests = len(self.results)
        passed_tests = sum(1 for r in self.results if r["success"])
        failed_tests = total_tests - passed_tests
        
        print("\n" + "=" * 60)
        print("📊 TEST SUMMARY")
        print("=" * 60)
        print(f"Total Tests: {total_tests}")
        print(f"✅ Passed: {passed_tests}")
        print(f"❌ Failed: {failed_tests}")
        print(f"Success Rate: {(passed_tests/total_tests*100):.1f}%")
        
        if failed_tests > 0:
            print("\n❌ FAILED TESTS:")
            for result in self.results:
                if not result["success"]:
                    print(f"  • {result['test']}: {result['details']}")
        
        print("\n" + "=" * 60)

if __name__ == "__main__":
    tester = BackendTester()
    success = tester.run_all_tests()
    tester.print_summary()
    
    if not success:
        exit(1)