#!/usr/bin/env python3
"""
E2E Smoke Test for Registration Flow
Performs a complete "Blind Test" of the registration-to-activation flow.
"""

import asyncio
import uuid
import httpx
import json
import time
from datetime import datetime
from typing import Dict, Any, Optional
import sys

# Configuration
API_BASE_URL = "http://sf_api:8000/api/v1"
MAILPIT_API = "http://sf_mailpit:8025/api/v1"

def generate_unique_email() -> str:
    """Generate a unique email for testing."""
    timestamp = int(time.time())
    random_id = uuid.uuid4().hex[:8]
    return f"test_{timestamp}_{random_id}@example.com"

async def call_registration(email: str) -> Dict[str, Any]:
    """Call the registration API endpoint."""
    async with httpx.AsyncClient(timeout=30.0) as client:
        payload = {
            "email": email,
            "password": "TestPassword123!",
            "first_name": "Test",
            "last_name": "User",
            "region_code": "HU",
            "lang": "hu"
        }
        
        print(f"📝 Registering user with email: {email}")
        response = await client.post(f"{API_BASE_URL}/auth/register", json=payload)
        
        if response.status_code != 201:
            print(f"❌ Registration failed: {response.status_code}")
            print(f"Response: {response.text}")
            return {"success": False, "error": f"HTTP {response.status_code}"}
        
        data = response.json()
        print(f"✅ Registration successful: {data.get('message')}")
        print(f"   User ID: {data.get('user_id')}")
        return {"success": True, "data": data}

async def get_verification_token_from_db(email: str) -> Optional[str]:
    """Get verification token directly from the database."""
    import os
    import asyncpg
    
    # Database connection parameters from environment
    db_host = os.getenv("DB_HOST", "shared-postgres")
    db_name = os.getenv("DB_NAME", "service_finder")
    db_user = os.getenv("DB_USER", "service_finder_app")
    db_password = os.getenv("DB_PASSWORD", "JELSZAVAD")
    
    try:
        # Connect to database
        conn = await asyncpg.connect(
            host=db_host,
            database=db_name,
            user=db_user,
            password=db_password
        )
        
        # Get user ID from email
        user_row = await conn.fetchrow(
            "SELECT id FROM identity.users WHERE email = $1",
            email
        )
        
        if not user_row:
            print(f"❌ User not found in database for email: {email}")
            return None
        
        user_id = user_row['id']
        
        # Get verification token
        token_row = await conn.fetchrow(
            """SELECT token FROM identity.verification_tokens 
               WHERE user_id = $1 AND token_type = 'registration' 
               ORDER BY created_at DESC LIMIT 1""",
            user_id
        )
        
        await conn.close()
        
        if token_row:
            token = str(token_row['token'])
            print(f"🔑 Found verification token in DB: {token[:8]}...")
            return token
        else:
            print("❌ No verification token found in database")
            return None
            
    except Exception as e:
        print(f"❌ Database error: {e}")
        return None

async def get_verification_token_from_mailpit(email: str) -> Optional[str]:
    """Try to get verification token from Mailpit API."""
    try:
        async with httpx.AsyncClient(timeout=10.0) as client:
            # Get latest messages
            response = await client.get(f"{MAILPIT_API}/messages")
            if response.status_code != 200:
                print(f"❌ Mailpit API error: {response.status_code}")
                return None
            
            messages = response.json().get('messages', [])
            
            # Find message sent to our test email
            for msg in messages:
                if msg.get('To', [{}])[0].get('Address') == email:
                    msg_id = msg['ID']
                    # Get message details
                    msg_response = await client.get(f"{MAILPIT_API}/message/{msg_id}")
                    if msg_response.status_code == 200:
                        msg_data = msg_response.json()
                        html = msg_data.get('HTML', '')
                        
                        # Extract token from HTML (look for token= parameter)
                        import re
                        token_match = re.search(r'token=([a-f0-9\-]+)', html)
                        if token_match:
                            token = token_match.group(1)
                            print(f"📧 Found verification token in email: {token[:8]}...")
                            return token
                        
                        # Also check text body
                        text = msg_data.get('Text', '')
                        token_match = re.search(r'token=([a-f0-9\-]+)', text)
                        if token_match:
                            token = token_match.group(1)
                            print(f"📧 Found verification token in email text: {token[:8]}...")
                            return token
            
            print("❌ No email found in Mailpit for the test address")
            return None
            
    except Exception as e:
        print(f"❌ Mailpit error: {e}")
        return None

async def verify_email(token: str) -> bool:
    """Call the verify-email endpoint."""
    async with httpx.AsyncClient(timeout=30.0) as client:
        payload = {"token": token}
        
        print(f"🔐 Verifying email with token: {token[:8]}...")
        response = await client.post(f"{API_BASE_URL}/auth/verify-email", json=payload)
        
        if response.status_code != 200:
            print(f"❌ Email verification failed: {response.status_code}")
            print(f"Response: {response.text}")
            return False
        
        data = response.json()
        print(f"✅ Email verification successful: {data.get('message')}")
        return True

async def check_user_activated(email: str) -> bool:
    """Check if user is activated in database."""
    import os
    import asyncpg
    
    db_host = os.getenv("DB_HOST", "shared-postgres")
    db_name = os.getenv("DB_NAME", "service_finder")
    db_user = os.getenv("DB_USER", "service_finder_app")
    db_password = os.getenv("DB_PASSWORD", "JELSZAVAD")
    
    try:
        conn = await asyncpg.connect(
            host=db_host,
            database=db_name,
            user=db_user,
            password=db_password
        )
        
        user_row = await conn.fetchrow(
            "SELECT is_active FROM identity.users WHERE email = $1",
            email
        )
        
        await conn.close()
        
        if user_row:
            is_active = user_row['is_active']
            print(f"👤 User activation status: {'ACTIVE' if is_active else 'INACTIVE'}")
            return is_active
        else:
            print("❌ User not found when checking activation")
            return False
            
    except Exception as e:
        print(f"❌ Database error checking activation: {e}")
        return False

async def main():
    """Main test execution."""
    print("=" * 60)
    print("🚀 Service Finder Registration E2E Smoke Test")
    print("=" * 60)
    
    # Generate unique test email
    test_email = generate_unique_email()
    print(f"📧 Test email: {test_email}")
    
    # Step 1: Register user
    print("\n1️⃣  Step 1: Registration")
    reg_result = await call_registration(test_email)
    if not reg_result["success"]:
        print("❌ TEST FAILED: Registration failed")
        return False
    
    # Wait a moment for email to be sent
    print("\n⏳ Waiting 3 seconds for email processing...")
    await asyncio.sleep(3)
    
    # Step 2: Get verification token
    print("\n2️⃣  Step 2: Token Retrieval")
    
    # Try database first (more reliable)
    token = await get_verification_token_from_db(test_email)
    
    # If not found in DB, try Mailpit
    if not token:
        print("⚠️  Token not found in DB, trying Mailpit...")
        token = await get_verification_token_from_mailpit(test_email)
    
    if not token:
        print("❌ TEST FAILED: Could not retrieve verification token")
        return False
    
    # Step 3: Verify email
    print("\n3️⃣  Step 3: Email Verification")
    verify_success = await verify_email(token)
    if not verify_success:
        print("❌ TEST FAILED: Email verification failed")
        return False
    
    # Step 4: Check user activation
    print("\n4️⃣  Step 4: Activation Verification")
    await asyncio.sleep(2)  # Give DB time to update
    is_active = await check_user_activated(test_email)
    
    if not is_active:
        print("❌ TEST FAILED: User not activated after verification")
        return False
    
    # Final report
    print("\n" + "=" * 60)
    print("✅ TEST PASSED: Registration-to-Activation flow is 100% OK")
    print("=" * 60)
    print(f"Summary:")
    print(f"  • Test email: {test_email}")
    print(f"  • Registration: ✅ Success")
    print(f"  • Token retrieval: ✅ Success")
    print(f"  • Email verification: ✅ Success")
    print(f"  • User activation: ✅ Success")
    print("=" * 60)
    
    return True

if __name__ == "__main__":
    # Install asyncpg if needed
    try:
        import asyncpg
    except ImportError:
        print("⚠️  asyncpg not installed. Installing...")
        import subprocess
        subprocess.check_call([sys.executable, "-m", "pip", "install", "asyncpg"])
        import asyncpg
    
    # Run the test
    success = asyncio.run(main())
    sys.exit(0 if success else 1)