#!/usr/bin/env python3
"""
WebSocket proxy server to forward Binance order book data to browser.
Browsers can't connect directly to Binance WebSocket (CORS + mixed content).
This proxy runs locally and forwards data to browser clients.
"""

import asyncio
import websockets
import json
from datetime import datetime

# Binance WebSocket URLs
BINANCE_WS_URLS = {
    'xautusdt': 'wss://stream.binance.com:9443/ws/xautusdt@depth20@100ms',
    'btcusdt': 'wss://stream.binance.com:9443/ws/btcusdt@depth20@100ms',
    'ethusdt': 'wss://stream.binance.com:9443/ws/ethusdt@depth20@100ms'
}

# Local server configuration
LOCAL_HOST = '0.0.0.0'
LOCAL_PORT = 8765

async def forward_binance_data(source_ws, dest_ws):
    """Forward data from Binance to browser."""
    try:
        async for message in source_ws:
            await dest_ws.send(message)
    except websockets.exceptions.ConnectionClosed:
        print(f"📴 Connection closed")
    except Exception as e:
        print(f"❌ Error forwarding data: {e}")

async def handle_client(websocket, path):
    """Handle incoming WebSocket connection from browser."""
    print(f"🔌 New client connected from {websocket.remote_address}")
    
    # Get requested asset from path (e.g., /xautusdt)
    asset = path.strip('/') if path else 'xautusdt'
    asset = asset.lower()
    
    if asset not in BINANCE_WS_URLS:
        await websocket.send(json.dumps({
            'error': f'Unknown asset: {asset}. Available: {list(BINANCE_WS_URLS.keys())}'
        }))
        await websocket.close()
        return
    
    binance_url = BINANCE_WS_URLS[asset]
    print(f"📡 Connecting to Binance: {binance_url}")
    
    try:
        # Connect to Binance WebSocket
        async with websockets.connect(binance_url) as binance_ws:
            print(f"✅ Connected to Binance for {asset.upper()}")
            
            # Send initial success message
            await websocket.send(json.dumps({
                'status': 'connected',
                'asset': asset.upper(),
                'timestamp': datetime.now().isoformat()
            }))
            
            # Forward data in both directions
            await asyncio.gather(
                forward_binance_data(binance_ws, websocket),
                # We don't need to forward client→Binance (read-only)
            )
            
    except websockets.exceptions.ConnectionClosed:
        print(f"📴 Client disconnected")
    except Exception as e:
        print(f"❌ Error: {e}")
        error_msg = json.dumps({'error': str(e)})
        try:
            await websocket.send(error_msg)
        except:
            pass

async def main():
    """Start WebSocket proxy server."""
    print(f"🚀 Starting Binance WebSocket Proxy Server")
    print(f"🌐 Local server: ws://{LOCAL_HOST}:{LOCAL_PORT}")
    print(f"📡 Forwarding to Binance WebSocket streams")
    print(f"📊 Available assets: {', '.join([a.upper() for a in BINANCE_WS_URLS.keys()])}")
    print()
    print(f"🔗 Browser URLs:")
    for asset in BINANCE_WS_URLS.keys():
        print(f"   ws://localhost:{LOCAL_PORT}/{asset}")
    print()
    print(f"Press Ctrl+C to stop")
    print()
    
    async with websockets.serve(handle_client, LOCAL_HOST, LOCAL_PORT):
        await asyncio.Future()  # Run forever

if __name__ == '__main__':
    try:
        asyncio.run(main())
    except KeyboardInterrupt:
        print("\n👋 Server stopped")