#!/usr/bin/env python3
"""
Email Unsubscriber - Automatyczne wypisywanie się z newsletterów.
"""
import os
import sys
import argparse
import email
from datetime import datetime, timedelta
from typing import List, Dict
from dotenv import load_dotenv

from llmass.imap import connect_imap
from llmass.organizer.parser import get_email_content, detect_imap_server
from llmass.unsubscribe import (
    detect_unsubscribe_link,
    extract_unsubscribe_info,
    is_newsletter,
    UnsubscribeBrowser,
    UnsubscribeLogger
)


class EmailUnsubscriber:
    """Automatyczne wypisywanie z newsletterów."""
    
    def __init__(self, email_address: str, password: str, imap_server: str = None):
        """Inicjalizacja."""
        self.email_address = email_address
        self.password = password
        self.imap_server = imap_server or detect_imap_server(email_address)
        self.imap = None
        self.client = None
        
        self.logger = UnsubscribeLogger()
    
    def connect(self):
        """Połączenie z serwerem IMAP."""
        try:
            self.client, self.imap = connect_imap(
                self.imap_server, self.email_address, self.password,
                ssl=True, retries=2, backoff=0.5, verbose=False
            )
            print(f"✅ Połączono z {self.imap_server}")
            return True
        except Exception as e:
            print(f"❌ Błąd połączenia: {e}")
            return False
    
    def detect_spam_folder(self) -> str:
        """
        Wykrywa nazwę folderu ze spamem.
        
        Returns:
            Nazwa folderu lub None jeśli nie znaleziono
        """
        # Możliwe nazwy folderów ze spamem
        spam_folder_names = [
            'SPAM', 'Spam', 'spam',
            'Junk', 'JUNK', 'junk',
            'Junk Email', 'Junk E-mail',
            'Bulk', 'BULK',
            'INBOX.Spam', 'INBOX.Junk',
            '[Gmail]/Spam',
        ]
        
        try:
            # Pobierz listę folderów
            result, folders = self.client.safe_list('', '*')
            if result != 'OK' or not folders:
                return None
            
            # Parse folder names
            available_folders = []
            for folder_line in folders:
                if not folder_line:
                    continue
                # Parse folder name from IMAP LIST response
                parts = folder_line.decode() if isinstance(folder_line, bytes) else folder_line
                # Extract folder name (last part after quotes or last word)
                import re
                match = re.search(r'"([^"]+)"$', parts)
                if match:
                    available_folders.append(match.group(1))
                else:
                    # Try to get last part
                    words = parts.split()
                    if words:
                        available_folders.append(words[-1])
            
            print(f"\n📁 Dostępne foldery: {', '.join(available_folders[:10])}{'...' if len(available_folders) > 10 else ''}")
            
            # Szukaj folderu spam
            for spam_name in spam_folder_names:
                if spam_name in available_folders:
                    print(f"✅ Znaleziono folder spamu: {spam_name}")
                    return spam_name
            
            # Szukaj case-insensitive
            for folder in available_folders:
                folder_lower = folder.lower()
                if 'spam' in folder_lower or 'junk' in folder_lower or 'bulk' in folder_lower:
                    print(f"✅ Znaleziono folder spamu: {folder}")
                    return folder
            
            print(f"⚠️  Nie znaleziono folderu spam. Sprawdź dostępne foldery powyżej.")
            return None
            
        except Exception as e:
            print(f"⚠️  Błąd wykrywania folderów: {e}")
            return None
    
    def disconnect(self):
        """Rozłączenie z serwerem."""
        if self.imap:
            try:
                self.imap.close()
                self.imap.logout()
                print("👋 Rozłączono z serwerem")
            except Exception:
                pass
    
    def find_newsletters(self, folder: str = "INBOX", limit: int = 100,
                        since_days: int = 30, deduplicate: bool = True) -> List[Dict]:
        """
        Znajduje newslettery w skrzynce.
        
        Args:
            folder: Folder do przeszukania
            limit: Maksymalna liczba emaili
            since_days: Ile dni wstecz szukać
            deduplicate: Czy deduplikować po nadawcy (tylko unikalni nadawcy)
        
        Returns:
            Lista słowników z informacjami o newsletterach
        """
        # Auto-detect spam folder if default "SPAM" provided
        if folder == "SPAM":
            detected_folder = self.detect_spam_folder()
            if detected_folder:
                folder = detected_folder
            else:
                print(f"\n💡 Podpowiedź: Użyj --folder INBOX lub nazwę swojego folderu spam")
                return []
        
        print(f"\n📧 Szukam newsletterów w folderze: {folder}\n")
        
        # Select folder
        result, data = self.client.safe_select(folder, readonly=True)
        if result != 'OK':
            print(f"❌ Nie można otworzyć folderu {folder}")
            print(f"💡 Sprawdź dostępne foldery powyżej lub użyj --folder z poprawną nazwą")
            return []
        
        # Search with date filter
        cutoff = datetime.now() - timedelta(days=since_days)
        search_str = cutoff.strftime('%d-%b-%Y')
        result, data = self.client.safe_uid('SEARCH', None, f'SINCE {search_str}')
        
        if result != 'OK' or not data or not data[0]:
            print("📭 Brak emaili do przetworzenia")
            return []
        
        email_ids = data[0].split()
        if not email_ids:
            print("📭 Brak emaili do przetworzenia")
            return []
        
        # Limit
        email_ids = email_ids[-limit:] if len(email_ids) > limit else email_ids
        print(f"📊 Znaleziono {len(email_ids)} emaili, sprawdzam...\n")
        
        newsletters = []
        seen_senders = set()  # Track unique senders for deduplication
        
        for idx, email_id in enumerate(email_ids, 1):
            try:
                # Fetch email
                result, data = self.client.safe_uid('FETCH', email_id, '(RFC822)')
                if result != 'OK' or not data or not data[0]:
                    continue
                
                raw_email = data[0][1]
                msg = email.message_from_bytes(raw_email)
                email_content = get_email_content(msg)
                
                # Check if newsletter
                if is_newsletter(email_content):
                    unsub_info = extract_unsubscribe_info(email_content)
                    
                    if unsub_info['has_unsubscribe']:
                        sender = unsub_info['sender']
                        
                        # Deduplicate by sender if requested
                        if deduplicate:
                            # Extract email address from sender (handle "Name <email>" format)
                            import re
                            email_match = re.search(r'<([^>]+)>', sender)
                            sender_email = email_match.group(1) if email_match else sender
                            
                            if sender_email in seen_senders:
                                print(f"⏭️  [{idx}/{len(email_ids)}] Duplikat: {sender[:50]} (pomijam)")
                                continue
                            
                            seen_senders.add(sender_email)
                        
                        print(f"✉️  [{idx}/{len(email_ids)}] Newsletter: {sender[:50]}")
                        print(f"    📋 {unsub_info['subject'][:60]}")
                        print(f"    🔗 {unsub_info['link'][:80]}")
                        newsletters.append(unsub_info)
                
            except Exception as e:
                print(f"⚠️  Błąd przetwarzania emaila {idx}: {e}")
                continue
        
        if deduplicate:
            print(f"\n📊 Znaleziono {len(newsletters)} unikalnych nadawców newsletterów z linkiem unsubscribe\n")
        else:
            print(f"\n📊 Znaleziono {len(newsletters)} newsletterów z linkiem unsubscribe\n")
        
        return newsletters
    
    def unsubscribe_all(self, newsletters: List[Dict], headless: bool = True,
                       dry_run: bool = False, open_in_browser: bool = False) -> List[Dict]:
        """
        Wypisuje się ze wszystkich znalezionych newsletterów.
        
        Args:
            newsletters: Lista informacji o newsletterach
            headless: Czy uruchomić przeglądarkę w trybie headless
            dry_run: Tylko symulacja, nie wykonuj akcji
            open_in_browser: Czy otworzyć linki również w domyślnej przeglądarce
        
        Returns:
            Lista rezultatów
        """
        if not newsletters:
            print("📭 Brak newsletterów do wypisania")
            return []
        
        if dry_run:
            print("🧪 [DRY-RUN MODE] Symulacja...")
            for n in newsletters:
                print(f"  📧 {n['sender']}")
                print(f"     🔗 {n['link']}")
            return []
        
        print(f"🚀 Rozpoczynam proces wypisywania z {len(newsletters)} newsletterów...\n")
        
        # Prepare URLs with info
        urls_with_info = [(n['link'], n) for n in newsletters if n['link']]
        
        # Run browser automation
        results = []
        try:
            with UnsubscribeBrowser(headless=headless) as browser:
                results = browser.batch_unsubscribe(urls_with_info, open_in_browser=open_in_browser)
        except Exception as e:
            print(f"❌ Błąd przeglądarki: {e}")
            print("💡 Zainstaluj Playwright: pip install playwright && playwright install chromium")
            return []
        
        # Log results
        self.logger.log_batch(results)
        
        # Print summary
        success_count = sum(1 for r in results if r['success'])
        fail_count = len(results) - success_count
        
        print(f"\n{'='*60}")
        print(f"📊 PODSUMOWANIE:")
        print(f"   ✅ Sukces: {success_count}")
        print(f"   ❌ Niepowodzenia: {fail_count}")
        print(f"   📄 Log zapisany: {self.logger.log_file}")
        
        # Show stats
        stats = self.logger.generate_stats()
        print(f"\n📈 STATYSTYKI CAŁKOWITE:")
        print(f"   Łącznie prób: {stats['total']}")
        print(f"   Skuteczność: {stats['success_rate']}%")
        print(f"{'='*60}\n")
        
        return results


def main():
    load_dotenv()
    
    parser = argparse.ArgumentParser(description='Email Unsubscriber - automatic newsletter unsubscribe')
    parser.add_argument('--email', help='Adres email', default=os.getenv('EMAIL_ADDRESS'))
    parser.add_argument('--password', help='Hasło', default=os.getenv('EMAIL_PASSWORD'))
    parser.add_argument('--imap-server', help='Serwer IMAP', default=os.getenv('IMAP_SERVER'))
    parser.add_argument('--folder', default='INBOX', help='Folder do przeszukania')
    parser.add_argument('--limit', type=int, default=100, help='Maksymalna liczba emaili do sprawdzenia')
    parser.add_argument('--since-days', type=int, default=30, help='Ile dni wstecz szukać')
    parser.add_argument('--dry-run', action='store_true', help='Tylko znajdź, nie wypisuj')
    parser.add_argument('--no-headless', action='store_true', help='Pokaż przeglądarkę (nie headless)')
    parser.add_argument('--stats', action='store_true', help='Pokaż tylko statystyki')
    
    args = parser.parse_args()
    
    if args.stats:
        # Show stats only
        logger = UnsubscribeLogger()
        stats = logger.generate_stats()
        print(f"\n📈 STATYSTYKI UNSUBSCRIBE:")
        print(f"   Łącznie prób: {stats['total']}")
        print(f"   Sukcesy: {stats['success']}")
        print(f"   Niepowodzenia: {stats['failed']}")
        print(f"   Skuteczność: {stats['success_rate']}%\n")
        
        failed_senders = logger.get_failed_senders()
        if failed_senders:
            print(f"❌ Nadawcy z nieudanymi próbami ({len(failed_senders)}):")
            for sender in failed_senders[:10]:
                print(f"   - {sender}")
        
        sys.exit(0)
    
    if not args.email or not args.password:
        print("❌ Brak danych logowania. Podaj --email/--password lub .env")
        sys.exit(1)
    
    unsubscriber = EmailUnsubscriber(args.email, args.password, args.imap_server)
    
    if unsubscriber.connect():
        try:
            # Find newsletters
            newsletters = unsubscriber.find_newsletters(
                folder=args.folder,
                limit=args.limit,
                since_days=args.since_days
            )
            
            if newsletters:
                # Unsubscribe
                results = unsubscriber.unsubscribe_all(
                    newsletters,
                    headless=not args.no_headless,
                    dry_run=args.dry_run
                )
            
        finally:
            unsubscriber.disconnect()


if __name__ == "__main__":
    main()
