"""
Test script for CCXT DataSource adapter (Free Version).

This demonstrates how to use the free CCXT adapter (not ccxt.pro) with various
exchanges. It uses polling instead of WebSocket for real-time updates.

CCXT is configured to use Decimal mode internally for precision, but OHLCV data
is converted to float for optimal DataFrame/analysis performance.
"""

import asyncio
from decimal import Decimal
from datetime import datetime, timedelta

from src.datasource.adapters.ccxt_adapter import CCXTDataSource


async def test_binance_datasource():
    """Test Binance exchange data source"""
    print("=" * 60)
    print("Testing CCXT DataSource with Binance (Free Version)")
    print("=" * 60)

    # Initialize Binance datasource with faster polling for testing
    binance = CCXTDataSource(exchange_id="binance", poll_interval=5)

    try:
        # Test 1: Get configuration
        print("\n1. Getting datafeed configuration...")
        config = await binance.get_config()
        print(f"   Name: {config.name}")
        print(f"   Description: {config.description}")
        print(f"   Supported resolutions: {config.supported_resolutions[:5]}...")
        print(f"   Exchanges: {config.exchanges}")

        # Test 2: Search symbols
        print("\n2. Searching for BTC symbols...")
        results = await binance.search_symbols("BTC", limit=5)
        print(f"   Found {len(results)} symbols:")
        for result in results[:3]:
            print(f"   - {result.symbol}: {result.description}")

        # Test 3: Resolve symbol
        print("\n3. Resolving symbol metadata for BTC/USDT...")
        symbol_info = await binance.resolve_symbol("BTC/USDT")
        print(f"   Symbol: {symbol_info.symbol}")
        print(f"   Name: {symbol_info.name}")
        print(f"   Type: {symbol_info.type}")
        print(f"   Exchange: {symbol_info.exchange}")
        print(f"   Columns:")
        for col in symbol_info.columns:
            print(f"     - {col.name} ({col.type}): {col.description}")

        # Test 4: Get historical bars
        print("\n4. Fetching historical 1-hour bars for BTC/USDT...")
        end_time = int(datetime.now().timestamp())
        start_time = end_time - (24 * 3600)  # Last 24 hours

        history = await binance.get_bars(
            symbol="BTC/USDT",
            resolution="60",  # 1 hour
            from_time=start_time,
            to_time=end_time,
            countback=10,
        )

        print(f"   Retrieved {len(history.bars)} bars")
        if history.bars:
            latest = history.bars[-1]
            print(f"   Latest bar:")
            print(f"     Time: {datetime.fromtimestamp(latest.time)}")
            print(f"     Open: {latest.data['open']} (type: {type(latest.data['open']).__name__})")
            print(f"     High: {latest.data['high']} (type: {type(latest.data['high']).__name__})")
            print(f"     Low: {latest.data['low']} (type: {type(latest.data['low']).__name__})")
            print(f"     Close: {latest.data['close']} (type: {type(latest.data['close']).__name__})")
            print(f"     Volume: {latest.data['volume']} (type: {type(latest.data['volume']).__name__})")

            # Verify OHLCV uses float (converted from Decimal for DataFrame performance)
            assert isinstance(latest.data['close'], float), "OHLCV price should be float type!"
            assert isinstance(latest.data['volume'], float), "OHLCV volume should be float type!"
            print(f"   ✓ OHLCV data type verified: using native float (CCXT uses Decimal internally)")

        # Test 5: Polling subscription (brief test)
        print("\n5. Testing polling-based subscription...")
        print(f"   Note: Using free CCXT with {binance._poll_interval}s polling interval")
        tick_count = [0]

        def on_tick(data):
            tick_count[0] += 1
            if tick_count[0] == 1:
                print(f"   Received tick: close={data['close']} (type: {type(data['close']).__name__})")
                assert isinstance(data['close'], float), "Polled OHLCV data should use float!"

        subscription_id = await binance.subscribe_bars(
            symbol="BTC/USDT",
            resolution="1",  # 1 minute
            on_tick=on_tick,
        )
        print(f"   Subscription ID: {subscription_id}")
        print(f"   Waiting {binance._poll_interval + 2} seconds for first poll...")

        await asyncio.sleep(binance._poll_interval + 2)

        # Unsubscribe
        await binance.unsubscribe_bars(subscription_id)
        print(f"   ✓ Subscription test complete (received {tick_count[0]} tick(s))")

    finally:
        await binance.close()
        print("\n✓ Binance datasource test complete")


async def test_multiple_exchanges():
    """Test multiple exchanges"""
    print("\n" + "=" * 60)
    print("Testing Multiple Exchanges")
    print("=" * 60)

    exchanges_to_test = ["binance", "coinbase", "kraken"]

    for exchange_id in exchanges_to_test:
        print(f"\nTesting {exchange_id}...")
        try:
            datasource = CCXTDataSource(exchange_id=exchange_id)
            config = await datasource.get_config()
            print(f"  ✓ {config.name}")

            # Try to search for ETH
            results = await datasource.search_symbols("ETH", limit=3)
            print(f"  ✓ Found {len(results)} ETH symbols")

            await datasource.close()

        except Exception as e:
            print(f"  ✗ Error: {e}")


async def main():
    """Run all tests"""
    print("\nCCXT DataSource Adapter Test Suite")
    print("=" * 60)

    try:
        await test_binance_datasource()
        await test_multiple_exchanges()

        print("\n" + "=" * 60)
        print("All tests completed successfully! ✓")
        print("=" * 60)

    except Exception as e:
        print(f"\n✗ Test failed: {e}")
        import traceback
        traceback.print_exc()


if __name__ == "__main__":
    asyncio.run(main())
