"""
Email Investigation Module
Enhanced email investigation with real API integrations and better analysis
"""

import asyncio
import aiohttp
import json
import re
import time
import hashlib
from urllib.parse import quote
from fake_useragent import UserAgent
from colorama import Fore, Style
import base64

class EmailInvestigator:
    """Email investigation module"""
    
    def __init__(self):
        self.ua = UserAgent()
        self.session = None
        self.timeout = 20  # Increased timeout
        self.max_retries = 5  # More retries
        
        # API endpoints
        self.hibp_api = "https://haveibeenpwned.com/api/v3/breachedaccount/{}"
        self.hunter_api = "https://api.hunter.io/v2/email-verifier?email={}&api_key={}"
        self.disposable_api = "https://disposable.debounce.io/?email={}"
        
        # Enhanced email patterns
        self.email_patterns = {
            'gmail': ['gmail.com', 'googlemail.com'],
            'yahoo': ['yahoo.com', 'yahoo.co.uk', 'yahoo.de', 'yahoo.fr'],
            'microsoft': ['hotmail.com', 'outlook.com', 'live.com', 'msn.com'],
            'apple': ['icloud.com', 'me.com', 'mac.com'],
            'professional': ['protonmail.com', 'tutanota.com', 'hushmail.com'],
            'corporate': [],  # Will be populated dynamically
            'security': ['keemail.me', 'countermail.com', 'scryptmail.com'],
            'gaming': ['gamemail.com', 'epicgames.com', 'steamgames.com'],
            'developer': ['devmail.com', 'codermail.com', 'gitmail.com']
        }
        
        # Track investigation results
        self.investigation_cache = {}
    
    def load_config(self):
        """Load configuration for API keys"""
        try:
            with open('config.json', 'r') as f:
                config = json.load(f)
                return config.get('api_keys', {})
        except:
            return {}
    
    def validate_email(self, email):
        """Enhanced email validation"""
        email_pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
        if not re.match(email_pattern, email):
            return False, "Invalid email format"
        
        # Additional checks
        local_part = email.split('@')[0]
        domain = email.split('@')[1].lower()
        
        if len(local_part) < 1 or len(local_part) > 64:
            return False, "Local part length invalid"
        
        if len(domain) < 4 or len(domain) > 253:
            return False, "Domain length invalid"
        
        return True, "Valid email format"
    
    async def check_email_disposability(self, email):
        """Check if email is from disposable service"""
        try:
            url = self.disposable_api.format(email)
            timeout = aiohttp.ClientTimeout(total=10)
            
            async with aiohttp.ClientSession(timeout=timeout) as session:
                async with session.get(url) as response:
                    if response.status == 200:
                        data = await response.json()
                        return {
                            "disposable": data.get("disposable", False),
                            "domain": data.get("domain", ""),
                            "mx_record": data.get("mx_record", False)
                        }
                    else:
                        return {"disposable": False, "error": "API unavailable"}
        except Exception as e:
            return {"disposable": False, "error": str(e)}
    
    async def check_hunter_verification(self, email):
        """Check email verification using Hunter.io"""
        api_keys = self.load_config()
        hunter_key = api_keys.get('hunter_io', '')
        
        if not hunter_key:
            return {"verified": None, "error": "Hunter.io API key not configured"}
        
        try:
            url = self.hunter_api.format(email, hunter_key)
            timeout = aiohttp.ClientTimeout(total=15)
            
            async with aiohttp.ClientSession(timeout=timeout) as session:
                async with session.get(url) as response:
                    if response.status == 200:
                        data = await response.json()
                        return {
                            "verified": data.get("data", {}).get("status"),
                            "score": data.get("data", {}).get("score"),
                            "regexp": data.get("data", {}).get("regexp"),
                            "gibberish": data.get("data", {}).get("gibberish"),
                            "disposable": data.get("data", {}).get("disposable"),
                            "webmail": data.get("data", {}).get("webmail"),
                            "accept_all": data.get("data", {}).get("accept_all"),
                            "sources": data.get("data", {}).get("sources", [])
                        }
                    else:
                        return {"verified": None, "error": f"API error: {response.status}"}
        except Exception as e:
            return {"verified": None, "error": str(e)}
    
    async def check_breaches_enhanced(self, email):
        """Enhanced breach checking with HaveIBeenPwned API"""
        api_keys = self.load_config()
        hibp_key = api_keys.get('haveibeenpwned', '')
        
        if not hibp_key:
            # Try to use the free public API (no key required)
            try:
                # Use the public breach API (limited but free)
                url = f"https://haveibeenpwned.com/api/v2/breachedaccount/{email}"
                timeout = aiohttp.ClientTimeout(total=10)
                
                async with aiohttp.ClientSession(timeout=timeout) as session:
                    headers = {"User-Agent": self.ua.random}
                    async with session.get(url, headers=headers) as response:
                        if response.status == 200:
                            data = await response.json()
                            return {
                                "breaches": data.get("breaches", []),
                                "pwned": data.get("breaches", []),
                                "total_breaches": len(data.get("breaches", [])),
                                "verified": data.get("verified", False),
                                "last_breach": data.get("last_breach"),
                                "note": "Using free public API (limited to recent breaches)"
                            }
                        elif response.status == 404:
                            return {
                                "breaches": [],
                                "pwned": False,
                                "total_breaches": 0,
                                "verified": False,
                                "note": "Email not found in breach databases"
                            }
                        else:
                            return {
                                "breaches": [],
                                "pwned": False,
                                "total_breaches": 0,
                                "error": f"Public API error: {response.status}",
                                "note": "Rate limited - try again later"
                            }
            except Exception as e:
                return {
                    "breaches": [],
                    "pwned": False,
                    "total_breach": 0,
                    "error": str(e),
                    "note": "Public API unavailable"
                }
        
        # If we have an API key, use the enhanced API
        try:
            # Create hash for the email
            sha1 = hashlib.sha1(email.encode('utf-8')).hexdigest().upper()
            prefix, suffix = sha1[:5], sha1[5:]
            
            # Use the searchable API
            url = f"https://api.pwnedpasswords.com/range/{prefix}"
            timeout = aiohttp.ClientTimeout(total=15)
            
            async with aiohttp.ClientSession(timeout=timeout) as session:
                headers = {"hibp-api-key": hibp_key}
                async with session.get(url, headers=headers) as response:
                    if response.status == 200:
                        data = await response.text()
                        breaches = []
                        
                        for line in data.split('\n'):
                            if line:
                                hash_suffix, count = line.split(':')
                                if hash_suffix == suffix:
                                    breaches.append({
                                        "type": "password_breach",
                                        "count": int(count)
                                    })
                                    break
                        
                        return {
                            "breaches": breaches,
                            "pwned": len(breaches) > 0,
                            "total_breaches": len(breaches),
                            "verified": True,
                            "note": "Using enhanced API with key"
                        }
                    else:
                        return {"breaches": [], "pwned": False, "error": f"API error: {response.status}"}
        except Exception as e:
            return {"breaches": [], "pwned": False, "error": str(e)}
    
    def analyze_domain_advanced(self, email):
        """Advanced domain analysis"""
        domain = email.split('@')[1].lower()
        
        # Check if it's a common provider
        provider_type = "custom"
        provider_name = domain
        
        for provider, domains in self.email_patterns.items():
            if domain in domains:
                provider_type = provider
                provider_name = provider.capitalize()
                break
        
        # Domain characteristics
        domain_info = {
            "domain": domain,
            "provider_type": provider_type,
            "provider_name": provider_name,
            "is_common_provider": provider_type != "custom",
            "tld": domain.split('.')[-1] if '.' in domain else "",
            "subdomain": len(domain.split('.')) > 2
        }
        
        # Additional analysis
        if provider_type == "custom":
            # Check for corporate indicators
            corporate_indicators = ['corp', 'inc', 'ltd', 'llc', 'company', 'business']
            domain_info["likely_corporate"] = any(indicator in domain for indicator in corporate_indicators)
        
        return domain_info
    
    async def search_social_associations(self, email, verbose=False):
        """Search for email associations on 200+ social media platforms"""
        if verbose:
            print(f"{Fore.CYAN}[*] Searching social media associations across 200+ platforms...{Style.RESET_ALL}")
        
        # Extract username from email (part before @)
        username = email.split('@')[0]
        
        # Use the same 200+ platforms as username search
        from .username_search import UsernameSearcher
        searcher = UsernameSearcher()
        
        # Search for the username on all platforms
        try:
            # Get all sites from username searcher
            sites = searcher.sites
            
            # Search with limited concurrency for email investigation
            semaphore = asyncio.Semaphore(10)  # Reduce concurrent requests for email
            
            async def check_site(site_name, site_config):
                async with semaphore:
                    try:
                        url = site_config["url"].format(username)
                        headers = site_config.get("headers", {})
                        headers["User-Agent"] = searcher.ua.random
                        
                        timeout = aiohttp.ClientTimeout(total=5)  # Shorter timeout for email investigation
                        async with aiohttp.ClientSession(timeout=timeout) as session:
                            async with session.get(url, headers=headers, ssl=False) as response:
                                if response.status == 200:
                                    content = await response.text()
                                    confidence = searcher.calculate_confidence(content, site_config, response.status)
                                    
                                    if confidence > 0.3:  # Found potential association
                                        return {
                                            "platform": site_name,
                                            "url": url,
                                            "confidence": confidence,
                                            "type": "username_match"
                                        }
                    except:
                        pass
                return None
            
            # Check all sites
            tasks = []
            for site_name, site_config in sites.items():
                task = check_site(site_name, site_config)
                tasks.append(task)
            
            # Execute with progress tracking
            found_associations = []
            completed = 0
            total = len(tasks)
            
            for coro in asyncio.as_completed(tasks):
                result = await coro
                if result:
                    found_associations.append(result)
                
                completed += 1
                if verbose and completed % 20 == 0:
                    print(f"{Fore.CYAN}[*] Checked {completed}/{total} platforms...{Style.RESET_ALL}")
            
            # Sort by confidence
            found_associations.sort(key=lambda x: x['confidence'], reverse=True)
            
            if verbose:
                print(f"{Fore.GREEN}[+] Found potential associations on {len(found_associations)} platforms{Style.RESET_ALL}")
            
            return {
                "total_found": len(found_associations),
                "associations": found_associations[:20],  # Return top 20
                "search_method": "username_extraction",
                "platforms_checked": total
            }
            
        except Exception as e:
            if verbose:
                print(f"{Fore.YELLOW}[!] Social media search failed: {str(e)[:50]}...{Style.RESET_ALL}")
            return {"total_found": 0, "associations": [], "error": str(e)}
    
    async def investigate_enhanced(self, email, verbose=False):
        # Validate email
        is_valid, validation_msg = self.validate_email(email)
        if not is_valid:
            raise ValueError(validation_msg)
        
        results = {
            "email": email,
            "timestamp": time.time(),
            "investigation": {},
            "enhanced": True
        }
        
        try:
            # Domain analysis
            if verbose:
                print(f"{Fore.CYAN}[*] Analyzing email domain...{Style.RESET_ALL}")
            
            domain_info = self.analyze_domain_advanced(email)
            results["investigation"]["domain_analysis"] = domain_info
            
            if verbose:
                pass
                    
            # Email verification
            if verbose:
                print(f"{Fore.CYAN}[*] Verifying email validity...{Style.RESET_ALL}")
            
            verification = await self.check_hunter_verification(email)
            results["investigation"]["verification"] = verification
            
            if verbose and verification.get("verified"):
                score = verification.get("score", 0)
                pass
            
            # Disposability check
            if verbose:
                print(f"{Fore.CYAN}[*] Checking if email is disposable...{Style.RESET_ALL}")
            
            disposable = await self.check_email_disposability(email)
            results["investigation"]["disposability"] = disposable
            
            if verbose:
                is_disposable = disposable.get("disposable", False)
                status = "Disposable" if is_disposable else "Not disposable"
                pass
            
            # Breach checking
            if verbose:
                print(f"{Fore.CYAN}[*] Checking data breaches...{Style.RESET_ALL}")
            
            breaches = await self.check_breaches_enhanced(email)
            results["investigation"]["breaches"] = breaches
            
            if verbose:
                pwned = breaches.get("pwned", False)
                if pwned:
                    pass
                else:
                    pass
            
            # Social media associations
            if verbose:
                print(f"{Fore.CYAN}[*] Searching social media associations...{Style.RESET_ALL}")
            
            social_results = await self.search_social_associations(email)
            results["investigation"]["social_associations"] = social_results
            
            if verbose:
                found_social = social_results.get("total_found", 0) if social_results else 0
                pass
            
            # Generate comprehensive summary
            results["summary"] = {
                "email": email,
                "valid": is_valid,
                "provider": domain_info.get("provider_name"),
                "provider_type": domain_info.get("provider_type"),
                "verification_score": verification.get("score") if verification else None,
                "is_disposable": disposable.get("disposable", False) if disposable else False,
                "breached": breaches.get("pwned", False) if breaches else False,
                "breach_count": breaches.get("total_breaches", 0) if breaches else 0,
                "social_associations": social_results.get("total_found", 0) if social_results else 0,
                "risk_level": self.calculate_risk_level(verification, disposable, breaches),
                "investigation_complete": True
            }
            
        except Exception as e:
            results["error"] = str(e)
            print(f"{Fore.RED}[-] Error during investigation: {str(e)}{Style.RESET_ALL}")
        
        return results
    
    def calculate_risk_level(self, verification, disposable, breaches):
        """Calculate risk level based on investigation results"""
        risk_score = 0
        
        # Verification score impact
        verif_score = verification.get("score", 50)
        if verif_score < 30:
            risk_score += 3
        elif verif_score < 60:
            risk_score += 2
        elif verif_score < 80:
            risk_score += 1
        
        # Disposability impact
        if disposable.get("disposable", False):
            risk_score += 2
        
        # Breach impact
        if breaches.get("pwned", False):
            breach_count = breaches.get("total_breaches", 0)
            if breach_count > 5:
                risk_score += 3
            elif breach_count > 2:
                risk_score += 2
            else:
                risk_score += 1
        
        # Determine risk level
        if risk_score >= 6:
            return "HIGH"
        elif risk_score >= 3:
            return "MEDIUM"
        else:
            return "LOW"
    
    async def investigate(self, email, verbose=False):
        """Main investigation method (backward compatibility)"""
        return await self.investigate_enhanced(email, verbose)
