"""
Main synchronous client for Nova Trading SDK

Example:
    >>> from nova_trading_sdk import NovaClient
    >>> client = NovaClient(api_key="your-api-key")
    >>> 
    >>> # Get ticker
    >>> ticker = client.get_ticker("BTCUSDT")
    >>> print(f"BTC: ${ticker['price']}")
    >>> 
    >>> # Get balance
    >>> balance = client.binance().balance()
    >>> print(f"USDT: {balance['balances']['USDT']['balance']}")
"""

import requests
from typing import Optional, Dict, Any, List, Union
from ..exceptions import NovaAPIError, AuthenticationError, ExchangeError

class NovaClient:
    """
    Main client for interacting with Nova Global Keys API
    
    Args:
        api_key: Your Nova Global Keys API key
        base_url: API base URL (default: https://api.novatradingkeys.com)
        timeout: Request timeout in seconds
    
    Example:
        >>> client = NovaClient(api_key="your-api-key")
        >>> ticker = client.get_ticker("BTCUSDT")
        >>> print(ticker['price'])
    """
    
    def __init__(
        self,
        api_key: str,
        base_url: str = "https://api.novatradingkeys.com",
        timeout: int = 30
    ):
        self.api_key = api_key
        self.base_url = base_url.rstrip('/')
        self.timeout = timeout
        self.session = requests.Session()
        self.session.headers.update({
            'Authorization': f'Bearer {api_key}',
            'Content-Type': 'application/json',
            'User-Agent': f'NovaSDK/2.0.0'
        })
    
    def _request(self, method: str, endpoint: str, **kwargs) -> Dict:
        """Make HTTP request to API"""
        url = f"{self.base_url}{endpoint}"
        kwargs.setdefault('timeout', self.timeout)
        
        try:
            response = self.session.request(method, url, **kwargs)
            data = response.json()
            
            if response.status_code == 401:
                raise AuthenticationError("Invalid API key")
            elif response.status_code >= 400:
                error_msg = data.get('detail', data.get('error', 'Unknown error'))
                raise NovaAPIError(f"API Error ({response.status_code}): {error_msg}")
            
            return data
        except requests.exceptions.RequestException as e:
            raise NovaAPIError(f"Request failed: {str(e)}")
    
    # ========================================================================
    # MARKET DATA ENDPOINTS
    # ========================================================================
    
    def get_ticker(self, symbol: str) -> Dict:
        """
        Get current ticker for a symbol
        
        Args:
            symbol: Trading pair symbol (e.g., 'BTCUSDT')
        
        Returns:
            Dict with price, change, high, low, volume
        
        Example:
            >>> ticker = client.get_ticker("BTCUSDT")
            >>> print(f"Price: ${ticker['price']}")
            >>> print(f"24h Change: {ticker['change_24h']}%")
        """
        return self._request('GET', f'/api/market/tickers/{symbol}')
    
    def get_orderbook(self, symbol: str, limit: int = 25) -> Dict:
        """
        Get order book for a symbol
        
        Args:
            symbol: Trading pair symbol
            limit: Number of bids/asks to return (default: 25)
        
        Returns:
            Dict with bids and asks arrays
        """
        return self._request('GET', f'/api/market/orderbook/{symbol}', 
                           params={'limit': limit})
    
    def get_klines(self, symbol: str, interval: str = '1h', limit: int = 100) -> List:
        """
        Get kline/candlestick data
        
        Args:
            symbol: Trading pair symbol
            interval: Candle interval (1m, 5m, 15m, 1h, 4h, 1d)
            limit: Number of candles to return
        
        Returns:
            List of kline data
        """
        return self._request('GET', '/api/market/klines', 
                           params={'symbol': symbol, 'interval': interval, 'limit': limit})
    
    # ========================================================================
    # ACCOUNT & BALANCE ENDPOINTS
    # ========================================================================
    
    def get_balance(self, exchange: str = None) -> Dict:
        """
        Get account balance for specified or all exchanges
        
        Args:
            exchange: Exchange name (bybit, binance, kucoin, okx) or None for all
        
        Returns:
            Dict with balances for each asset
        
        Example:
            >>> # Get all balances
            >>> all_balances = client.get_balance()
            >>> 
            >>> # Get only Binance balance
            >>> binance_balance = client.get_balance('binance')
        """
        if exchange:
            return self._request('GET', f'/api/{exchange}/balance')
        return self._request('GET', '/api/balance/all')
    
    def get_exchanges(self) -> List[str]:
        """Get list of connected exchanges"""
        return self._request('GET', '/api/exchanges')
    
    # ========================================================================
    # TRADING ENDPOINTS
    # ========================================================================
    
    def place_order(
        self,
        exchange: str,
        symbol: str,
        side: str,
        quantity: float,
        order_type: str = 'market',
        price: float = None
    ) -> Dict:
        """
        Place an order on specified exchange
        
        Args:
            exchange: Exchange name (bybit, binance, kucoin, okx)
            symbol: Trading pair symbol
            side: 'buy' or 'sell'
            quantity: Amount to trade
            order_type: 'market' or 'limit'
            price: Required for limit orders
        
        Returns:
            Dict with order details
        
        Example:
            >>> # Market buy
            >>> order = client.place_order('binance', 'BTCUSDT', 'buy', 0.001)
            >>> print(f"Order ID: {order['order_id']}")
            >>> 
            >>> # Limit sell
            >>> order = client.place_order('bybit', 'BTCUSDT', 'sell', 0.001, 
            ...                          order_type='limit', price=50000)
        """
        data = {
            'exchange': exchange,
            'symbol': symbol,
            'side': side,
            'order_type': order_type,
            'quantity': quantity
        }
        if price:
            data['price'] = price
        
        return self._request('POST', '/api/trade/order', json=data)
    
    def cancel_order(self, exchange: str, symbol: str, order_id: str) -> Dict:
        """
        Cancel an open order
        
        Args:
            exchange: Exchange name
            symbol: Trading pair symbol
            order_id: ID of order to cancel
        
        Returns:
            Dict with cancellation confirmation
        """
        return self._request('POST', '/api/trade/order/cancel',
                           json={'exchange': exchange, 'symbol': symbol, 'order_id': order_id})
    
    def get_open_orders(self, exchange: str, symbol: str = None) -> List:
        """
        Get open orders from exchange
        
        Args:
            exchange: Exchange name
            symbol: Optional symbol filter
        
        Returns:
            List of open orders
        """
        params = {'exchange': exchange}
        if symbol:
            params['symbol'] = symbol
        return self._request('GET', '/api/trade/orders/open', params=params)
    
    def get_order_history(self, exchange: str, symbol: str = None, limit: int = 50) -> List:
        """
        Get order history from exchange
        
        Args:
            exchange: Exchange name
            symbol: Optional symbol filter
            limit: Number of orders to return
        
        Returns:
            List of historical orders
        """
        params = {'exchange': exchange, 'limit': limit}
        if symbol:
            params['symbol'] = symbol
        return self._request('GET', '/api/trade/orders/history', params=params)
    
    # ========================================================================
    # P2P ENDPOINTS
    # ========================================================================
    
    def get_p2p_balance(self, exchange: str = 'bybit') -> Dict:
        """Get P2P balance from exchange"""
        return self._request('GET', f'/api/p2p/balance', params={'exchange': exchange})
    
    def get_p2p_orders(self, exchange: str = 'bybit', status: str = None) -> List:
        """Get P2P orders from exchange"""
        params = {'exchange': exchange}
        if status:
            params['status'] = status
        return self._request('GET', '/api/p2p/orders', params=params)
    
    # ========================================================================
    # BROKER ENDPOINTS (Admin/Master Key Required)
    # ========================================================================
    
    def create_subaccount(self, username: str, member_type: int = 1) -> Dict:
        """Create a subaccount (master key required)"""
        return self._request('POST', '/api/broker/subaccount/create',
                           json={'username': username, 'member_type': member_type})
    
    def get_subaccounts(self) -> List:
        """Get list of subaccounts (master key required)"""
        return self._request('GET', '/api/broker/subaccount/list')
    
    # ========================================================================
    # EXCHANGE-SPECIFIC PROXIES
    # ========================================================================
    
    def bybit(self):
        """Access Bybit-specific methods"""
        return ExchangeProxy(self, 'bybit')
    
    def binance(self):
        """Access Binance-specific methods"""
        return ExchangeProxy(self, 'binance')
    
    def kucoin(self):
        """Access KuCoin-specific methods"""
        return ExchangeProxy(self, 'kucoin')
    
    def okx(self):
        """Access OKX-specific methods"""
        return ExchangeProxy(self, 'okx')


class ExchangeProxy:
    """Proxy for exchange-specific operations"""
    
    def __init__(self, client: NovaClient, exchange: str):
        self._client = client
        self._exchange = exchange
    
    def balance(self) -> Dict:
        """Get balance for this exchange"""
        return self._client.get_balance(self._exchange)
    
    def ticker(self, symbol: str) -> Dict:
        """Get ticker from this exchange"""
        return self._client._request('GET', f'/api/{self._exchange}/ticker/{symbol}')
    
    def place_order(self, symbol: str, side: str, quantity: float, 
                   order_type: str = 'market', price: float = None) -> Dict:
        """Place order on this exchange"""
        return self._client.place_order(
            self._exchange, symbol, side, quantity, order_type, price
        )
    
    def open_orders(self, symbol: str = None) -> List:
        """Get open orders on this exchange"""
        return self._client.get_open_orders(self._exchange, symbol)
    
    def cancel_order(self, symbol: str, order_id: str) -> Dict:
        """Cancel order on this exchange"""
        return self._client.cancel_order(self._exchange, symbol, order_id)
