#!/usr/bin/env python3
"""
Test suite completa per i provider attivi di fba_finance
Verifica affidabilità, performance e compatibilità
"""
import sys
import time
from datetime import datetime, timedelta

sys.path.insert(0, '/Users/faustobandini/Library/CloudStorage/OneDrive-Personale/Sviluppo/IA/fba_finance')

from fba_finance import FinanceClient, Config
from fba_finance.providers.yfinance_provider import YFinanceProvider
from fba_finance.providers.yahooquery_provider import YahooQueryProvider
from fba_finance.core.rate_limiter import ProviderRateLimiter

# Test symbols
TEST_SYMBOLS_SINGLE = ["AAPL", "MSFT", "GOOGL"]
TEST_SYMBOLS_BATCH = ["AAPL", "MSFT", "GOOGL", "AMZN", "META", "TSLA", "NVDA", "JPM", "V", "WMT"]


class ProviderTester:
    """Test runner per un provider specifico"""
    
    def __init__(self, provider_name, provider_instance):
        self.name = provider_name
        self.provider = provider_instance
        self.results = {
            "available": False,
            "quote_success": 0,
            "quote_failures": 0,
            "batch_success": False,
            "batch_count": 0,
            "historical_success": False,
            "avg_response_time": 0,
            "errors": []
        }
    
    def test_availability(self):
        """Test se il provider è disponibile"""
        print(f"\n[{self.name}] Test disponibilità...")
        self.results["available"] = self.provider.available
        if self.results["available"]:
            print(f"  ✅ {self.name} disponibile")
        else:
            print(f"  ⚠️  {self.name} non disponibile: {self.provider.last_error}")
        return self.results["available"]
    
    def test_single_quotes(self):
        """Test quote singole"""
        if not self.results["available"]:
            return
        
        print(f"\n[{self.name}] Test quote singole...")
        times = []
        
        for symbol in TEST_SYMBOLS_SINGLE:
            start = time.time()
            try:
                quote = self.provider.get_quote(symbol)
                elapsed = time.time() - start
                times.append(elapsed)
                
                if quote and quote.price:
                    self.results["quote_success"] += 1
                    print(f"  ✅ {symbol}: ${quote.price:.2f} ({elapsed:.2f}s)")
                else:
                    self.results["quote_failures"] += 1
                    print(f"  ❌ {symbol}: No data ({elapsed:.2f}s)")
            except Exception as e:
                elapsed = time.time() - start
                self.results["quote_failures"] += 1
                self.results["errors"].append(f"get_quote({symbol}): {e}")
                print(f"  ❌ {symbol}: Error - {e} ({elapsed:.2f}s)")
            
            time.sleep(0.3)  # Rate limiting
        
        if times:
            self.results["avg_response_time"] = sum(times) / len(times)
    
    def test_batch_quotes(self):
        """Test quote batch"""
        if not self.results["available"]:
            return
        
        print(f"\n[{self.name}] Test batch quotes...")
        start = time.time()
        
        try:
            quotes = self.provider.get_multiple_quotes(TEST_SYMBOLS_BATCH)
            elapsed = time.time() - start
            
            self.results["batch_success"] = len(quotes) > 0
            self.results["batch_count"] = len(quotes)
            
            print(f"  ✅ Batch: {len(quotes)}/{len(TEST_SYMBOLS_BATCH)} quotes in {elapsed:.2f}s")
            print(f"     Velocità: {len(quotes)/elapsed:.1f} quotes/sec")
            
            # Mostra primi 3
            for quote in quotes[:3]:
                print(f"     {quote.symbol}: ${quote.price:.2f}")
                
        except Exception as e:
            elapsed = time.time() - start
            self.results["errors"].append(f"get_multiple_quotes: {e}")
            print(f"  ❌ Batch error: {e} ({elapsed:.2f}s)")
    
    def test_historical(self):
        """Test dati storici"""
        if not self.results["available"]:
            return
        
        print(f"\n[{self.name}] Test dati storici...")
        symbol = "AAPL"
        end = datetime.now()
        start = end - timedelta(days=7)
        
        try:
            start_time = time.time()
            hist = self.provider.get_historical(symbol, start, end)
            elapsed = time.time() - start_time
            
            if hist and hist.data is not None and not hist.data.empty:
                self.results["historical_success"] = True
                print(f"  ✅ Historical: {len(hist.data)} records ({elapsed:.2f}s)")
                print(f"     Range: {hist.start_date} to {hist.end_date}")
            else:
                print(f"  ❌ Historical: No data ({elapsed:.2f}s)")
                
        except Exception as e:
            self.results["errors"].append(f"get_historical: {e}")
            print(f"  ❌ Historical error: {e}")
    
    def run_all_tests(self):
        """Esegue tutti i test"""
        print("=" * 70)
        print(f"TEST PROVIDER: {self.name.upper()}")
        print("=" * 70)
        
        if self.test_availability():
            self.test_single_quotes()
            self.test_batch_quotes()
            self.test_historical()
        
        return self.results
    
    def print_summary(self):
        """Stampa riepilogo risultati"""
        r = self.results
        print(f"\n📊 RIEPILOGO {self.name.upper()}:")
        print(f"   Disponibile: {'✅' if r['available'] else '❌'}")
        if r['available']:
            print(f"   Quote singole: {r['quote_success']}/{r['quote_success'] + r['quote_failures']}")
            print(f"   Batch: {'✅' if r['batch_success'] else '❌'} ({r['batch_count']} quotes)")
            print(f"   Historical: {'✅' if r['historical_success'] else '❌'}")
            print(f"   Tempo medio: {r['avg_response_time']:.2f}s")
            if r['errors']:
                print(f"   ⚠️  Errori: {len(r['errors'])}")


def test_all_providers():
    """Test completo di tutti i provider"""
    print("=" * 70)
    print("TEST SUITE COMPLETA - TUTTI I PROVIDER")
    print("=" * 70)
    print(f"Data: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
    print(f"Test symbols singoli: {', '.join(TEST_SYMBOLS_SINGLE)}")
    print(f"Test symbols batch: {len(TEST_SYMBOLS_BATCH)} simboli")
    
    rate_limiter = ProviderRateLimiter()
    
    # Inizializza provider (yahoo_scraper disabilitato per instabilità)
    providers = [
        ("yfinance", YFinanceProvider(rate_limiter)),
        ("yahooquery", YahooQueryProvider(rate_limiter)),
    ]
    
    # Aggiungi twelvedata e alphavantage se disponibili
    try:
        from fba_finance.providers.twelvedata_provider import TwelveDataProvider
        providers.append(("twelvedata", TwelveDataProvider(rate_limiter=rate_limiter)))
    except Exception as e:
        print(f"\n⚠️  TwelveData provider non disponibile: {e}")
    
    try:
        from fba_finance.providers.alphavantage_provider import AlphaVantageProvider
        providers.append(("alphavantage", AlphaVantageProvider(rate_limiter=rate_limiter)))
    except Exception as e:
        print(f"\n⚠️  AlphaVantage provider non disponibile: {e}")
    
    # Esegui test
    results = {}
    testers = []
    
    for name, provider in providers:
        tester = ProviderTester(name, provider)
        results[name] = tester.run_all_tests()
        testers.append(tester)
        time.sleep(1)  # Pausa tra provider
    
    # Riepilogo finale
    print("\n" + "=" * 70)
    print("RIEPILOGO FINALE")
    print("=" * 70)
    
    for tester in testers:
        tester.print_summary()
    
    # Classifica provider
    print("\n" + "=" * 70)
    print("CLASSIFICA AFFIDABILITÀ")
    print("=" * 70)
    
    ranked = []
    for name, res in results.items():
        if res["available"]:
            score = 0
            score += res["quote_success"] * 10
            score += (10 if res["batch_success"] else 0)
            score += (10 if res["historical_success"] else 0)
            score -= res["quote_failures"] * 5
            score -= len(res["errors"]) * 3
            # Bonus per velocità
            if res["avg_response_time"] > 0:
                score += max(0, 10 - int(res["avg_response_time"]))
            
            ranked.append((name, score, res))
    
    ranked.sort(key=lambda x: x[1], reverse=True)
    
    for i, (name, score, res) in enumerate(ranked, 1):
        print(f"{i}. {name.upper()}: {score} punti")
        print(f"   Quote: {res['quote_success']}/{res['quote_success'] + res['quote_failures']}, "
              f"Batch: {res['batch_count']}, "
              f"Historical: {'✅' if res['historical_success'] else '❌'}, "
              f"Tempo: {res['avg_response_time']:.2f}s")
    
    # Raccomandazioni
    print("\n" + "=" * 70)
    print("RACCOMANDAZIONI")
    print("=" * 70)
    
    if ranked:
        best = ranked[0]
        print(f"🥇 Provider consigliato: {best[0].upper()}")
        print(f"   Motivo: {best[1]} punti di affidabilità")
        
        # Suggerisci priority order
        priority = [name for name, _, _ in ranked]
        print(f"\n📋 PROVIDER_PRIORITY suggerito:")
        print(f"   Config.PROVIDER_PRIORITY = {priority}")
    
    return results


def test_finance_client_integration():
    """Test integrazione con FinanceClient"""
    print("\n" + "=" * 70)
    print("TEST INTEGRAZIONE FINANCE CLIENT")
    print("=" * 70)
    
    client = FinanceClient()
    
    # Test fallback automatico
    print("\n[FALLBACK TEST] Quote con fallback automatico...")
    symbols = ["AAPL", "MSFT", "INVALID_SYMBOL_12345"]
    
    start = time.time()
    quotes = client.get_quotes(symbols)
    elapsed = time.time() - start
    
    print(f"  ✅ Ricevute {len(quotes)}/{len(symbols)} quotes in {elapsed:.2f}s")
    for symbol, quote in quotes.items():
        print(f"     {symbol}: ${quote.price:.2f} from {quote.source}")
    
    # Test load balancing
    print("\n[LOAD BALANCING TEST] Round-robin mode...")
    Config.LOAD_BALANCING_MODE = "round-robin"
    client_rr = FinanceClient()
    
    quotes_rr = client_rr.get_quotes(["AAPL", "MSFT", "GOOGL", "AMZN"])
    
    sources = {}
    for quote in quotes_rr.values():
        sources[quote.source] = sources.get(quote.source, 0) + 1
    
    print(f"  Provider utilizzati: {sources}")
    
    Config.LOAD_BALANCING_MODE = "fallback"  # Reset


if __name__ == "__main__":
    try:
        # Test 1: Tutti i provider
        results = test_all_providers()
        
        # Test 2: Integrazione client
        test_finance_client_integration()
        
        print("\n" + "=" * 70)
        print("✅ TEST SUITE COMPLETATA CON SUCCESSO")
        print("=" * 70)
        
    except KeyboardInterrupt:
        print("\n\n⚠️  Test interrotti dall'utente")
    except Exception as e:
        print(f"\n\n❌ Errore durante i test: {e}")
        import traceback
        traceback.print_exc()
