"""
Integracja z zewnętrznymi bazami danych SPAM do lepszej detekcji.

Wspierane źródła:
1. SpamHaus ZEN (DNS blacklist)
2. SURBL (Spam URI Realtime Blacklists)
3. Local spam patterns cache
"""

import re
import socket
from typing import Dict, List, Set, Optional, Tuple
from urllib.parse import urlparse
from datetime import datetime, timedelta
import os

# Cache dla DNS lookupów (aby nie spamować DNS serwerów)
_dns_cache: Dict[str, tuple] = {}  # domain -> (is_blacklisted, timestamp)
_cache_ttl = timedelta(hours=24)


def extract_domains_from_email(email_content: Dict) -> Set[str]:
    """Wyciąga domeny z URL-i w emailu."""
    domains = set()
    
    # Get all text
    text = f"{email_content.get('subject', '')} {email_content.get('body', '')}"
    
    # Find URLs
    url_pattern = r'https?://[^\s<>"{}|\\^`\[\]]+'
    urls = re.findall(url_pattern, text, re.IGNORECASE)
    
    for url in urls:
        try:
            parsed = urlparse(url)
            if parsed.netloc:
                # Remove www. prefix
                domain = parsed.netloc.lower()
                domain = domain.replace('www.', '')
                domains.add(domain)
        except Exception:
            continue
    
    # Also check From domain
    from_email = email_content.get('from', '')
    if '@' in from_email:
        match = re.search(r'@([^\s>]+)', from_email)
        if match:
            domains.add(match.group(1).lower())
    
    return domains


def check_spamhaus_zen(domain: str) -> bool:
    """
    Sprawdza domenę w SpamHaus ZEN (DNS blacklist).
    
    ZEN combines: SBL, XBL, PBL
    Query: <reversed-ip>.zen.spamhaus.org
    
    Returns True if domain is blacklisted.
    """
    # Check cache first
    now = datetime.now()
    if domain in _dns_cache:
        result, timestamp = _dns_cache[domain]
        if now - timestamp < _cache_ttl:
            return result
    
    try:
        # Try to resolve domain to IP first
        try:
            ip = socket.gethostbyname(domain)
        except socket.gaierror:
            # Domain doesn't resolve, skip check
            _dns_cache[domain] = (False, now)
            return False
        
        # Reverse IP for DNSBL query
        parts = ip.split('.')
        reversed_ip = '.'.join(reversed(parts))
        
        # Query SpamHaus ZEN
        query_domain = f"{reversed_ip}.zen.spamhaus.org"
        
        try:
            socket.gethostbyname(query_domain)
            # If lookup succeeds, IP is blacklisted
            _dns_cache[domain] = (True, now)
            return True
        except socket.gaierror:
            # Not blacklisted
            _dns_cache[domain] = (False, now)
            return False
    except Exception:
        # On any error, assume not blacklisted but don't cache
        return False


def check_surbl(domain: str) -> bool:
    """
    Sprawdza domenę w SURBL (Spam URI Realtime Blacklists).
    
    Query: <domain>.multi.surbl.org
    
    Returns True if domain is blacklisted.
    """
    # Check cache
    now = datetime.now()
    cache_key = f"surbl_{domain}"
    if cache_key in _dns_cache:
        result, timestamp = _dns_cache[cache_key]
        if now - timestamp < _cache_ttl:
            return result
    
    try:
        query_domain = f"{domain}.multi.surbl.org"
        
        try:
            socket.gethostbyname(query_domain)
            # Domain is in SURBL
            _dns_cache[cache_key] = (True, now)
            return True
        except socket.gaierror:
            # Not in SURBL
            _dns_cache[cache_key] = (False, now)
            return False
    except Exception:
        return False


def check_uribl(domain: str) -> bool:
    """
    Sprawdza domenę w URIBL (another major spam URI blacklist).
    
    Query: <domain>.black.uribl.com
    
    Returns True if domain is blacklisted.
    """
    # Check cache
    now = datetime.now()
    cache_key = f"uribl_{domain}"
    if cache_key in _dns_cache:
        result, timestamp = _dns_cache[cache_key]
        if now - timestamp < _cache_ttl:
            return result
    
    try:
        query_domain = f"{domain}.black.uribl.com"
        
        try:
            socket.gethostbyname(query_domain)
            # Domain is in URIBL
            _dns_cache[cache_key] = (True, now)
            return True
        except socket.gaierror:
            # Not in URIBL
            _dns_cache[cache_key] = (False, now)
            return False
    except Exception:
        return False


def check_spam_databases(email_content: Dict, verbose: bool = False) -> Tuple[bool, List[str]]:
    """
    Sprawdza email w zewnętrznych bazach danych SPAM.
    
    Returns:
        (is_spam, reasons) where reasons is list of detection sources
    """
    reasons = []
    
    # Extract domains from email
    domains = extract_domains_from_email(email_content)
    
    if not domains:
        return False, reasons
    
    # Check each domain against blacklists
    for domain in domains:
        # Skip common legitimate domains
        if domain in {'google.com', 'gmail.com', 'yahoo.com', 'outlook.com', 
                     'microsoft.com', 'apple.com', 'amazon.com', 'facebook.com'}:
            continue
        
        # SpamHaus ZEN check
        if check_spamhaus_zen(domain):
            reason = f"SpamHaus ZEN: {domain}"
            reasons.append(reason)
            if verbose:
                print(f"  🚫 {reason}")
        
        # SURBL check
        if check_surbl(domain):
            reason = f"SURBL: {domain}"
            reasons.append(reason)
            if verbose:
                print(f"  🚫 {reason}")
        
        # URIBL check
        if check_uribl(domain):
            reason = f"URIBL: {domain}"
            reasons.append(reason)
            if verbose:
                print(f"  🚫 {reason}")
    
    is_spam = len(reasons) > 0
    return is_spam, reasons


def enhanced_spam_check(email_content: Dict, verbose: bool = False) -> Tuple[bool, str]:
    """
    Enhanced spam check combining local heuristics with online databases.
    
    Returns:
        (is_spam, reason) tuple
    """
    # First check local heuristics (from filters.py)
    from llmass.organizer.filters import is_spam_local
    
    if is_spam_local(email_content):
        return True, "Local heuristics"
    
    # Then check online databases
    is_db_spam, reasons = check_spam_databases(email_content, verbose=verbose)
    
    if is_db_spam:
        reason = ", ".join(reasons)
        return True, f"Blacklisted: {reason}"
    
    return False, ""


# Environment variable to enable/disable online checks
def is_online_spam_check_enabled() -> bool:
    """Check if online spam database checks are enabled."""
    return os.getenv('SPAM_ONLINE_CHECK', 'true').lower() in ('true', '1', 'yes')
