"""
Domain Analysis Module
Enhanced domain analysis with better DNS enumeration and comprehensive analysis
"""

import asyncio
import aiohttp
import whois
import dns.resolver
import dns.exception
import socket
import ssl
import time
import re
from urllib.parse import urlparse
from fake_useragent import UserAgent
from colorama import Fore, Style
import json

class DomainAnalyzer:
    """Domain analysis module"""
    
    def __init__(self):
        self.ua = UserAgent()
        self.session = None
        self.timeout = 25  # Increased timeout for DNS operations
        self.max_retries = 5  # More retries for network operations
        
        # Enhanced common subdomains for enumeration
        self.common_subdomains = [
            # Infrastructure
            "www", "mail", "email", "ftp", "ssh", "vpn", "remote", "portal",
            "ns1", "ns2", "ns3", "ns4", "mx", "mx1", "mx2", "smtp", "pop", "imap",
            # Development
            "dev", "development", "test", "testing", "staging", "stage", "beta", "alpha",
            "demo", "sandbox", "preview", "preprod", "prod", "production",
            # Services
            "api", "app", "apps", "web", "webmail", "cpanel", "admin", "administrator",
            "dashboard", "console", "panel", "control", "manage", "management",
            # Business
            "shop", "store", "ecommerce", "cart", "checkout", "payment", "billing",
            "sales", "crm", "erp", "hr", "finance", "accounting",
            # Content
            "blog", "news", "forum", "wiki", "docs", "help", "support", "faq",
            "knowledge", "learn", "education", "training", "tutorial",
            # Security
            "secure", "ssl", "cert", "certificate", "auth", "oauth",
            "login", "signin", "register", "signup", "2fa", "mfa",
            # Regional
            "us", "eu", "asia", "uk", "de", "fr", "jp", "cn",
            "na", "sa", "af", "au", "ca", "mx", "br", "in",
            # CDN/Cloud
            "cdn", "cloud", "static", "assets", "media", "images", "files",
            "js", "css", "fonts", "resources", "content", "downloads",
            # Database
            "db", "database", "sql", "mysql", "postgres", "mongo",
            "redis", "elasticsearch", "cassandra", "oracle",
            # Monitoring
            "monitor", "metrics", "logs", "analytics", "stats",
            "ping", "health", "status", "uptime", "performance",
            # Modern/Cloud
            "k8s", "kubernetes", "docker", "container", "microservice",
            "lambda", "serverless", "function", "edge", "worker",
            # IoT/Devices
            "iot", "device", "sensor", "gateway", "edge", "embedded",
            "smart", "connected", "things", "mesh", "network"
        ]
        
        # DNS record types to query
        self.dns_record_types = ['A', 'AAAA', 'MX', 'NS', 'TXT', 'CNAME', 'SOA', 'PTR', 'SRV', 'CAA']
        
        # Technology detection patterns
        self.tech_patterns = {
            'web_server': [
                (r'apache', 'Apache'),
                (r'nginx', 'Nginx'),
                (r'iis', 'Microsoft IIS'),
                (r'lighttpd', 'Lighttpd'),
                (r'caddy', 'Caddy')
            ],
            'cms': [
                (r'wordpress', 'WordPress'),
                (r'drupal', 'Drupal'),
                (r'joomla', 'Joomla'),
                (r'magento', 'Magento'),
                (r'shopify', 'Shopify'),
                (r'ghost', 'Ghost')
            ],
            'framework': [
                (r'react', 'React'),
                (r'vue', 'Vue.js'),
                (r'angular', 'Angular'),
                (r'django', 'Django'),
                (r'flask', 'Flask'),
                (r'rails', 'Ruby on Rails')
            ],
            'analytics': [
                (r'google-analytics', 'Google Analytics'),
                (r'gtm', 'Google Tag Manager'),
                (r'hotjar', 'Hotjar'),
                (r'mixpanel', 'Mixpanel'),
                (r'segment', 'Segment')
            ]
        }
        
        # Cache for results
        self.dns_cache = {}
    
    def validate_domain(self, domain):
        """Enhanced domain validation"""
        # Clean domain input
        if domain.startswith(('http://', 'https://')):
            parsed = urlparse(domain)
            domain = parsed.netloc
        
        # Remove www prefix for analysis
        if domain.startswith('www.'):
            domain = domain[4:]
        
        # Basic validation
        domain_pattern = r'^[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?)*$'
        if not re.match(domain_pattern, domain):
            return False, "Invalid domain format"
        
        return True, domain.lower()
    
    async def enhanced_whois_lookup(self, domain):
        """Enhanced WHOIS lookup with better error handling"""
        try:
            w = whois.whois(domain)
            
            # Extract and clean WHOIS data
            whois_data = {
                "registrar": getattr(w, 'registrar', None),
                "creation_date": str(w.creation_date) if w.creation_date else None,
                "expiration_date": str(w.expiration_date) if w.expiration_date else None,
                "updated_date": str(w.updated_date) if w.updated_date else None,
                "name_servers": getattr(w, 'name_servers', []),
                "status": getattr(w, 'status', []),
                "registrant": getattr(w, 'org', None) or getattr(w, 'name', None),
                "country": getattr(w, 'country', None),
                "admin_email": getattr(w, 'admin_email', None),
                "tech_email": getattr(w, 'tech_email', None),
                "dnssec": getattr(w, 'dnssec', None)
            }
            
            # Calculate domain age
            if w.creation_date:
                if isinstance(w.creation_date, list):
                    creation_date = w.creation_date[0]
                else:
                    creation_date = w.creation_date
                
                domain_age = (time.time() - creation_date.timestamp()) / (365.25 * 24 * 3600)
                whois_data["domain_age_years"] = round(domain_age, 2)
            
            return whois_data
            
        except Exception as e:
            return {"error": f"WHOIS lookup failed: {str(e)}"}
    
    async def comprehensive_dns_enumeration(self, domain):
        """Comprehensive DNS record enumeration"""
        records = {}
        
        # Record types to query
        record_types = [
            'A', 'AAAA', 'MX', 'NS', 'TXT', 'CNAME', 'SOA', 'PTR',
            'SRV', 'CAA', 'DNSKEY', 'DS', 'NSEC', 'RRSIG'
        ]
        
        for record_type in record_types:
            try:
                answers = dns.resolver.resolve(domain, record_type, raise_on_no_answer=False)
                if answers:
                    records[record_type] = [str(rdata) for rdata in answers]
                else:
                    records[record_type] = []
            except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer, dns.exception.DNSException):
                records[record_type] = []
            except Exception as e:
                records[record_type] = [{"error": str(e)}]
        
        # Additional DNS queries
        try:
            # Zone transfer attempt (for security testing)
            zone_records = []
            try:
                answers = dns.resolver.resolve(domain, 'AXFR')
                zone_records = [str(rdata) for rdata in answers]
            except:
                pass  # Zone transfers are usually blocked
            
            records["zone_transfer"] = {
                "attempted": True,
                "successful": len(zone_records) > 0,
                "records": zone_records[:10] if zone_records else []  # Limit output
            }
        except Exception as e:
            records["zone_transfer"] = {"attempted": False, "error": str(e)}
        
        return records
    
    async def advanced_subdomain_enumeration(self, domain):
        """Advanced subdomain enumeration with multiple techniques"""
        found_subdomains = []
        enumeration_methods = {
            "brute_force": [],
            "dns_transfer": [],
            "search_engines": [],
            "certificate_transparency": []
        }
        
        # Method 1: Brute force common subdomains
        
        semaphore = asyncio.Semaphore(20)  # Limit concurrent DNS queries
        
        async def check_subdomain(subdomain):
            full_domain = f"{subdomain}.{domain}"
            try:
                async with semaphore:
                    answers = dns.resolver.resolve(full_domain, 'A', timeout=2)
                    if answers:
                        return {
                            "subdomain": full_domain,
                            "ip": str(answers[0]),
                            "method": "brute_force"
                        }
            except:
                pass
            return None
        
        # Check common subdomains in batches
        tasks = []
        for subdomain in self.common_subdomains[:50]:  # Limit to first 50 for speed
            task = check_subdomain(subdomain)
            tasks.append(task)
        
        results = await asyncio.gather(*tasks, return_exceptions=True)
        for result in results:
            if result and isinstance(result, dict):
                found_subdomains.append(result)
                enumeration_methods["brute_force"].append(result["subdomain"])
        
        # Method 2: Certificate transparency logs (simplified)
        try:
            # This would normally use services like crt.sh or censys
            # For now, we'll provide the framework
            ct_url = f"https://crt.sh/?q=%.{domain}&output=json"
            timeout = aiohttp.ClientTimeout(total=10)
            
            async with aiohttp.ClientSession(timeout=timeout) as session:
                async with session.get(ct_url) as response:
                    if response.status == 200:
                        try:
                            ct_data = await response.json()
                            for cert in ct_data[:20]:  # Limit results
                                name_value = cert.get('name_value', '')
                                if name_value and name_value != domain:
                                    if name_value not in found_subdomains:
                                        found_subdomains.append({
                                            "subdomain": name_value,
                                            "method": "certificate_transparency"
                                        })
                                        enumeration_methods["certificate_transparency"].append(name_value)
                        except:
                            pass
        except Exception as e:
            pass
        
        return {
            "total_found": len(found_subdomains),
            "subdomains": found_subdomains,
            "enumeration_methods": enumeration_methods,
            "note": f"Checked {len(self.common_subdomains)} common subdomains via brute force"
        }
    
    async def enhanced_http_analysis(self, domain):
        """Enhanced HTTP analysis with security headers and technology detection"""
        results = {}
        
        # Test both HTTP and HTTPS
        protocols = ['http', 'https']
        
        for protocol in protocols:
            url = f"{protocol}://{domain}"
            try:
                timeout = aiohttp.ClientTimeout(total=self.timeout)
                connector = aiohttp.TCPConnector(limit=10, limit_per_host=2)
                
                async with aiohttp.ClientSession(connector=connector, timeout=timeout) as session:
                    headers = {
                        "User-Agent": self.ua.random,
                        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
                        "Accept-Language": "en-US,en;q=0.9",
                        "Accept-Encoding": "gzip, deflate, br",
                        "DNT": "1",
                        "Connection": "keep-alive",
                        "Upgrade-Insecure-Requests": "1"
                    }
                    
                    async with session.get(url, headers=headers, allow_redirects=True, ssl=False) as response:
                        content = await response.text()
                        response_headers = dict(response.headers)
                        
                        # Analyze response
                        analysis = {
                            "status_code": response.status,
                            "final_url": str(response.url),
                            "response_time": response.headers.get("X-Response-Time", "N/A"),
                            "content_length": len(content),
                            "content_type": response_headers.get("Content-Type", ""),
                            "server": response_headers.get("Server", ""),
                            "powered_by": response_headers.get("X-Powered-By", ""),
                            "headers": response_headers
                        }
                        
                        # Security headers analysis
                        security_headers = {
                            "strict_transport_security": response_headers.get("Strict-Transport-Security"),
                            "content_security_policy": response_headers.get("Content-Security-Policy"),
                            "x_frame_options": response_headers.get("X-Frame-Options"),
                            "x_content_type_options": response_headers.get("X-Content-Type-Options"),
                            "x_xss_protection": response_headers.get("X-XSS-Protection"),
                            "referrer_policy": response_headers.get("Referrer-Policy"),
                            "permissions_policy": response_headers.get("Permissions-Policy")
                        }
                        
                        # Calculate security score
                        security_score = 0
                        for header, value in security_headers.items():
                            if value:
                                security_score += 1
                        
                        analysis["security_headers"] = security_headers
                        analysis["security_score"] = f"{security_score}/7"
                        
                        # Technology detection
                        technologies = []
                        for category, patterns in self.tech_patterns.items():
                            for pattern, tech in patterns:
                                if re.search(pattern, content, re.IGNORECASE):
                                    technologies.append({
                                        "name": tech,
                                        "category": category,
                                        "confidence": "high" if tech.lower() in content.lower() else "medium"
                                    })
                        
                        analysis["technologies"] = technologies
                        
                        # SSL/TLS analysis for HTTPS
                        if protocol == "https":
                            try:
                                ssl_info = await self.analyze_ssl_certificate(domain)
                                analysis["ssl_certificate"] = ssl_info
                            except Exception as e:
                                analysis["ssl_certificate"] = {"error": str(e)}
                        
                        results[protocol] = analysis
                        
            except asyncio.TimeoutError:
                results[protocol] = {"error": "Timeout", "status_code": None}
            except Exception as e:
                results[protocol] = {"error": str(e), "status_code": None}
        
        return results
    
    async def analyze_ssl_certificate(self, domain):
        """Analyze SSL certificate information"""
        try:
            context = ssl.create_default_context()
            context.check_hostname = False
            context.verify_mode = ssl.CERT_NONE
            
            with socket.create_connection((domain, 443), timeout=10) as sock:
                with context.wrap_socket(sock, server_hostname=domain) as ssock:
                    cert = ssock.getpeercert()
                    
                    return {
                        "subject": dict(x[0] for x in cert.get('subject', [])),
                        "issuer": dict(x[0] for x in cert.get('issuer', [])),
                        "version": cert.get('version'),
                        "serial_number": cert.get('serialNumber'),
                        "not_before": cert.get('notBefore'),
                        "not_after": cert.get('notAfter'),
                        "subject_alt_names": cert.get('subjectAltName', []),
                        "signature_algorithm": cert.get('signatureAlgorithm'),
                        "valid_days": self.calculate_ssl_validity(cert.get('notAfter'))
                    }
        except Exception as e:
            return {"error": f"SSL analysis failed: {str(e)}"}
    
    def calculate_ssl_validity(self, not_after_str):
        """Calculate SSL certificate validity in days"""
        try:
            from datetime import datetime
            import dateutil.parser
            
            not_after = dateutil.parser.parse(not_after_str)
            now = datetime.now(not_after.tzinfo)
            delta = not_after - now
            return delta.days
        except:
            return "Unknown"
    
    async def analyze_enhanced(self, domain, verbose=False):
        """Enhanced domain analysis with all features"""
        
        # Validate domain
        is_valid, clean_domain = self.validate_domain(domain)
        if not is_valid:
            raise ValueError(clean_domain)  # clean_domain contains error message
        
        results = {
            "domain": clean_domain,
            "timestamp": time.time(),
            "analysis": {},
            "enhanced": True
        }
        
        try:
            # WHOIS analysis
            if verbose:
                pass
            
            whois_info = await self.enhanced_whois_lookup(clean_domain)
            results["analysis"]["whois"] = whois_info
            
            if verbose and "error" not in whois_info:
                registrar = whois_info.get("registrar", "Unknown")
                age = whois_info.get("domain_age_years", "Unknown")
            
            # DNS enumeration
            if verbose:
                pass
            
            dns_records = await self.comprehensive_dns_enumeration(clean_domain)
            results["analysis"]["dns"] = dns_records
            
            if verbose:
                pass
                total_records = sum(len(records) for records in dns_records.values() if isinstance(records, list))
            
            # Subdomain enumeration
            if verbose:
                pass
            
            subdomain_info = await self.advanced_subdomain_enumeration(clean_domain)
            results["analysis"]["subdomains"] = subdomain_info
            
            if verbose:
                pass
                found_count = subdomain_info["total_found"]
            
            # HTTP analysis
            if verbose:
                pass
            
            http_info = await self.enhanced_http_analysis(clean_domain)
            results["analysis"]["http"] = http_info
            
            if verbose:
                pass
            
            # Generate comprehensive summary
            results["summary"] = {
                "domain": clean_domain,
                "registrar": whois_info.get("registrar"),
                "domain_age": whois_info.get("domain_age_years"),
                "dns_record_types": len([k for k, v in dns_records.items() if isinstance(v, list) and v]),
                "total_dns_records": sum(len(v) for v in dns_records.values() if isinstance(v, list)),
                "subdomains_found": subdomain_info["total_found"],
                "technologies_detected": len(set(
                    tech["name"] for info in http_info.values() 
                    if "technologies" in info 
                    for tech in info["technologies"]
                )),
                "security_score": next(
                    (info.get("security_score", "0/7") for info in http_info.values() 
                     if "security_score" in info), "0/7"
                ),
                "ssl_valid": any(
                    isinstance(info.get("ssl_certificate", {}).get("valid_days", 0), int) and 
                    info.get("ssl_certificate", {}).get("valid_days", 0) > 0 
                    for info in http_info.values() 
                    if "ssl_certificate" in info
                ),
                "analysis_complete": True
            }
            
        except Exception as e:
            results["error"] = str(e)
            print(f"{Fore.RED}[-] Error during analysis: {str(e)}{Style.RESET_ALL}")
        
        return results
    
    async def analyze(self, domain, verbose=False):
        """Main analysis method (backward compatibility)"""
        return await self.analyze_enhanced(domain, verbose)
