"""
Client ApolloX Finance pour trading degen
Wrapper autour de apollox-connector-python
"""

import logging
from typing import List, Dict, Optional
import pandas as pd
import numpy as np
from datetime import datetime, timedelta

try:
    from apollox.rest_api import Client as ApolloXClient
except ImportError:
    print("⚠️  apollox-connector-python non installé. Installez avec: pip install apollox-connector-python")
    ApolloXClient = None

import config


class ApolloDegenClient:
    """Client pour trading degen sur ApolloX"""

    def __init__(self, api_key: str = None, api_secret: str = None, testnet: bool = False):
        self.logger = logging.getLogger(self.__class__.__name__)

        # Credentials
        self.api_key = api_key or config.APOLLOX_API_KEY
        self.api_secret = api_secret or config.APOLLOX_API_SECRET

        if not ApolloXClient:
            raise ImportError("apollox-connector-python requis")

        # Créer client
        if self.api_key and self.api_secret:
            self.client = ApolloXClient(key=self.api_key, secret=self.api_secret)
            self.logger.info("✅ Client ApolloX authentifié")
        else:
            self.client = ApolloXClient()
            self.logger.warning("⚠️  Client ApolloX en mode public (market data seulement)")

    # ==================== MARKET DATA ====================

    def get_klines(self, symbol: str, interval: str, limit: int = 100) -> pd.DataFrame:
        """
        Récupère les chandeliers

        Args:
            symbol: Symbole (ex: BTCUSDT)
            interval: Timeframe (1m, 5m, 15m, 1h, etc.)
            limit: Nombre de chandeliers (max 1500)

        Returns:
            DataFrame avec colonnes: timestamp, open, high, low, close, volume
        """
        try:
            klines = self.client.klines(symbol=symbol, interval=interval, limit=limit)

            # Convertir en DataFrame
            df = pd.DataFrame(klines, columns=[
                'timestamp', 'open', 'high', 'low', 'close', 'volume',
                'close_time', 'quote_volume', 'trades', 'taker_buy_base',
                'taker_buy_quote', 'ignore'
            ])

            # Nettoyer et convertir types
            df['timestamp'] = pd.to_datetime(df['timestamp'], unit='ms')
            for col in ['open', 'high', 'low', 'close', 'volume']:
                df[col] = df[col].astype(float)

            # Garder seulement les colonnes utiles
            df = df[['timestamp', 'open', 'high', 'low', 'close', 'volume']]

            return df

        except Exception as e:
            self.logger.error(f"Erreur récupération klines {symbol} {interval}: {e}")
            return pd.DataFrame()

    def get_ticker(self, symbol: str) -> Dict:
        """Récupère le ticker 24h pour un symbole"""
        try:
            ticker = self.client.ticker_24hr_price_change(symbol=symbol)
            return ticker
        except Exception as e:
            self.logger.error(f"Erreur récupération ticker {symbol}: {e}")
            return {}

    def get_orderbook(self, symbol: str, limit: int = 20) -> Dict:
        """Récupère l'orderbook"""
        try:
            orderbook = self.client.depth(symbol=symbol, limit=limit)
            return orderbook
        except Exception as e:
            self.logger.error(f"Erreur récupération orderbook {symbol}: {e}")
            return {}

    def get_all_tickers(self) -> List[Dict]:
        """Récupère tous les tickers (pour scanner de shitcoins)"""
        try:
            tickers = self.client.ticker_price()
            return tickers
        except Exception as e:
            self.logger.error(f"Erreur récupération tickers: {e}")
            return []

    # ==================== ACCOUNT & POSITIONS ====================

    def get_account(self) -> Dict:
        """Récupère les infos du compte"""
        try:
            account = self.client.account()
            return account
        except Exception as e:
            self.logger.error(f"Erreur récupération account: {e}")
            return {}

    def get_balance(self) -> float:
        """Récupère la balance USDT"""
        try:
            account = self.get_account()
            for asset in account.get('assets', []):
                if asset['asset'] == 'USDT':
                    return float(asset['availableBalance'])
            return 0.0
        except Exception as e:
            self.logger.error(f"Erreur récupération balance: {e}")
            return 0.0

    def get_positions(self) -> List[Dict]:
        """Récupère les positions ouvertes"""
        try:
            account = self.get_account()
            positions = account.get('positions', [])

            # Filtrer seulement les positions avec quantité non nulle
            active_positions = [
                pos for pos in positions
                if float(pos.get('positionAmt', 0)) != 0
            ]

            return active_positions
        except Exception as e:
            self.logger.error(f"Erreur récupération positions: {e}")
            return []

    # ==================== TRADING ====================

    def set_leverage(self, symbol: str, leverage: int):
        """Configure le leverage pour un symbole"""
        try:
            result = self.client.change_leverage(symbol=symbol, leverage=leverage)
            self.logger.info(f"✅ Leverage {symbol}: {leverage}x")
            return result
        except Exception as e:
            self.logger.error(f"❌ Erreur set leverage {symbol} {leverage}x: {e}")
            return None

    def set_margin_type(self, symbol: str, margin_type: str = 'ISOLATED'):
        """Configure le type de marge (ISOLATED ou CROSSED)"""
        try:
            result = self.client.change_margin_type(symbol=symbol, marginType=margin_type)
            self.logger.info(f"✅ Margin type {symbol}: {margin_type}")
            return result
        except Exception as e:
            # Erreur si déjà configuré - on ignore
            if 'No need to change margin type' in str(e):
                self.logger.debug(f"Margin type {symbol} déjà {margin_type}")
                return True
            self.logger.error(f"❌ Erreur set margin type {symbol}: {e}")
            return None

    def place_market_order(self, symbol: str, side: str, quantity: float,
                          reduce_only: bool = False) -> Optional[Dict]:
        """
        Place un ordre market

        Args:
            symbol: Symbole (BTCUSDT)
            side: BUY ou SELL
            quantity: Quantité en tokens
            reduce_only: Si True, ordre de fermeture seulement
        """
        try:
            params = {
                'symbol': symbol,
                'side': side,
                'type': 'MARKET',
                'quantity': quantity
            }

            if reduce_only:
                params['reduceOnly'] = 'true'

            order = self.client.new_order(**params)
            self.logger.info(f"✅ Ordre {side} {quantity} {symbol} exécuté")
            return order

        except Exception as e:
            self.logger.error(f"❌ Erreur place order {side} {quantity} {symbol}: {e}")
            return None

    def place_limit_order(self, symbol: str, side: str, quantity: float,
                         price: float, reduce_only: bool = False) -> Optional[Dict]:
        """Place un ordre limit"""
        try:
            params = {
                'symbol': symbol,
                'side': side,
                'type': 'LIMIT',
                'timeInForce': 'GTC',
                'quantity': quantity,
                'price': price
            }

            if reduce_only:
                params['reduceOnly'] = 'true'

            order = self.client.new_order(**params)
            self.logger.info(f"✅ Ordre LIMIT {side} {quantity} {symbol} @ {price}")
            return order

        except Exception as e:
            self.logger.error(f"❌ Erreur limit order: {e}")
            return None

    def place_stop_loss(self, symbol: str, side: str, quantity: float,
                       stop_price: float) -> Optional[Dict]:
        """
        Place un stop-loss

        Args:
            side: Opposé à la position (BUY pour short, SELL pour long)
        """
        try:
            params = {
                'symbol': symbol,
                'side': side,
                'type': 'STOP_MARKET',
                'stopPrice': stop_price,
                'quantity': quantity,
                'reduceOnly': 'true'
            }

            order = self.client.new_order(**params)
            self.logger.info(f"✅ Stop-loss {symbol} @ {stop_price}")
            return order

        except Exception as e:
            self.logger.error(f"❌ Erreur stop-loss: {e}")
            return None

    def place_take_profit(self, symbol: str, side: str, quantity: float,
                         price: float) -> Optional[Dict]:
        """Place un take-profit"""
        try:
            params = {
                'symbol': symbol,
                'side': side,
                'type': 'TAKE_PROFIT_MARKET',
                'stopPrice': price,
                'quantity': quantity,
                'reduceOnly': 'true'
            }

            order = self.client.new_order(**params)
            self.logger.info(f"✅ Take-profit {symbol} @ {price}")
            return order

        except Exception as e:
            self.logger.error(f"❌ Erreur take-profit: {e}")
            return None

    def cancel_all_orders(self, symbol: str):
        """Annule tous les ordres ouverts pour un symbole"""
        try:
            result = self.client.cancel_open_orders(symbol=symbol)
            self.logger.info(f"✅ Ordres annulés pour {symbol}")
            return result
        except Exception as e:
            self.logger.error(f"❌ Erreur annulation ordres: {e}")
            return None

    def close_position(self, symbol: str, side: str, quantity: float) -> Optional[Dict]:
        """
        Ferme une position

        Args:
            side: LONG ou SHORT
            quantity: Quantité absolue
        """
        # Pour fermer: LONG = SELL, SHORT = BUY
        close_side = 'SELL' if side == 'LONG' else 'BUY'

        return self.place_market_order(
            symbol=symbol,
            side=close_side,
            quantity=abs(quantity),
            reduce_only=True
        )


if __name__ == '__main__':
    # Test basique
    logging.basicConfig(level=logging.INFO)

    client = ApolloDegenClient()

    # Test market data
    print("\n📊 Test market data...")
    df = client.get_klines('BTCUSDT', '1m', limit=10)
    print(df.tail())

    ticker = client.get_ticker('BTCUSDT')
    print(f"\nBTC Price: ${float(ticker.get('lastPrice', 0)):,.2f}")
    print(f"24h Change: {float(ticker.get('priceChangePercent', 0)):+.2f}%")
