#!/usr/bin/env python3
"""
Degen Scalping Bot - Mode ULTRA DEGEN (225x)
Bot de scalping autonome avec la stratégie ultra-stricte

ATTENTION: Leverage extrême! À utiliser avec précaution.
"""

import time
import logging
from datetime import datetime
from degen_scalping_strategy import DegenScalpingStrategy
from price_feed import BinancePriceFeed
from apollox_v2_client import ApolloXV2Client
import os
from dotenv import load_dotenv
import json

logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - [%(name)s] - %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S'
)
logger = logging.getLogger(__name__)

# Silence some loggers
logging.getLogger('apollox_v2_client').setLevel(logging.WARNING)


class DegenScalpBot:
    """Bot de scalping ultra-degen (225x leverage)"""

    def __init__(self, dry_run: bool = True):
        """
        Args:
            dry_run: Si True, ne trade pas réellement (mode simulation)
        """
        self.dry_run = dry_run
        self.strategy = DegenScalpingStrategy()
        self.feed = BinancePriceFeed()

        # Load env
        load_dotenv()

        # Init ApolloX client si pas dry run
        if not dry_run:
            private_key = os.getenv('WALLET_PRIVATE_KEY')
            self.client = ApolloXV2Client(private_key=private_key)
            self.wallet = self.client.account.address
        else:
            self.client = None
            self.wallet = "DRY_RUN"

        # Position actuelle
        self.current_position = None

        # Stats
        self.stats = {
            'signals_checked': 0,
            'signals_generated': 0,
            'trades_opened': 0,
            'trades_closed': 0,
            'wins': 0,
            'losses': 0,
            'total_pnl': 0.0
        }

        logger.info("="*80)
        logger.info("🎯 DEGEN SCALP BOT INITIALIZED")
        logger.info("="*80)
        logger.info(f"   Mode: {'DRY RUN (simulation)' if dry_run else 'LIVE TRADING'}")
        logger.info(f"   Wallet: {self.wallet}")
        logger.info(f"   Leverage: {self.strategy.leverage}x")
        logger.info(f"   TP: {self.strategy.take_profit_pct*100:.3f}% = +{self.strategy.take_profit_pct*self.strategy.leverage*100:.1f}% profit")
        logger.info(f"   SL: {self.strategy.stop_loss_pct*100:.3f}% = -{self.strategy.stop_loss_pct*self.strategy.leverage*100:.1f}% perte")
        logger.info("="*80)

    def run(self, check_interval: int = 30):
        """
        Lance le bot

        Args:
            check_interval: Intervalle entre chaque vérification (secondes)
        """
        logger.info(f"\n🚀 Bot démarré - Vérification toutes les {check_interval}s")
        logger.info(f"   Appuyez sur Ctrl+C pour arrêter\n")

        try:
            while True:
                self._check_and_trade()
                time.sleep(check_interval)

        except KeyboardInterrupt:
            logger.info(f"\n\n👋 Arrêt du bot...")
            self._print_stats()

    def _check_and_trade(self):
        """Vérifie les signaux et trade si conditions remplies"""

        logger.info("="*80)
        logger.info(f"🔍 CHECK #{self.stats['signals_checked'] + 1}")
        logger.info("="*80)

        try:
            # 1. Récupérer données
            df = self.feed.get_klines("BTCUSDT", "1m", 100)

            if df is None:
                logger.error("❌ Impossible de récupérer les données")
                return

            current_price = df['close'].iloc[-1]
            volatility = (df['high'].tail(5).max() - df['low'].tail(5).min()) / current_price

            logger.info(f"📊 BTC: ${current_price:,.2f} | Vol: {volatility*100:.2f}%")

            self.stats['signals_checked'] += 1

            # 2. Vérifier position existante
            if self.current_position:
                self._check_exit(current_price)
                return  # Ne cherche pas de nouveau signal si position ouverte

            # 3. Analyser
            signal = self.strategy.analyze('BTCUSD_DEGEN', df)

            if signal:
                self.stats['signals_generated'] += 1
                logger.info(f"\n🎯 SIGNAL DÉTECTÉ!")
                logger.info(f"   {signal.side} @ ${signal.entry_price:,.2f}")
                logger.info(f"   Confiance: {signal.confidence:.1f}%")

                # Ouvrir position
                self._open_position(signal)
            else:
                logger.info(f"   ⏳ Pas de signal - En attente setup parfait...")

        except Exception as e:
            logger.error(f"❌ Erreur check: {e}", exc_info=True)

    def _open_position(self, signal):
        """Ouvre une position"""

        logger.info(f"\n{'='*80}")
        logger.info(f"📈 OUVERTURE POSITION {signal.side}")
        logger.info(f"{'='*80}")
        logger.info(f"   Entry: ${signal.entry_price:,.2f}")
        logger.info(f"   TP: ${signal.take_profit:,.2f} (+{abs(signal.take_profit - signal.entry_price)/signal.entry_price*100:.2f}%)")
        logger.info(f"   SL: ${signal.stop_loss:,.2f} (-{abs(signal.stop_loss - signal.entry_price)/signal.entry_price*100:.3f}%)")
        logger.info(f"   Leverage: {signal.leverage}x")

        if self.dry_run:
            logger.info(f"\n   🎭 DRY RUN - Position simulée (pas de trade réel)")
            self.current_position = {
                'signal': signal,
                'entry_price': signal.entry_price,
                'entry_time': datetime.now(),
                'dry_run': True
            }
            self.stats['trades_opened'] += 1
        else:
            # LIVE TRADING - Ouverture réelle via ApolloX
            logger.warning(f"\n   🚨 LIVE TRADING - POSITION RÉELLE!")

            # Calculer margin (95% du capital disponible)
            # Note: Pour ApolloX, on devrait vérifier le balance réel
            margin_usd = 2.0 * 0.95  # $2 USDT * 95%

            # Ouvrir position on-chain
            trade_hash = self.client.open_position(
                pair='BTC',
                is_long=(signal.side == 'LONG'),
                margin_usd=margin_usd,
                leverage=signal.leverage,
                price=signal.entry_price,
                stop_loss=signal.stop_loss,
                take_profit=signal.take_profit
            )

            if trade_hash:
                logger.info(f"   ✅ Position ouverte! Hash: {trade_hash}")
                self.current_position = {
                    'signal': signal,
                    'entry_price': signal.entry_price,
                    'entry_time': datetime.now(),
                    'trade_hash': trade_hash,
                    'dry_run': False
                }
                self.stats['trades_opened'] += 1
            else:
                logger.error(f"   ❌ Échec ouverture position!")
                return

        logger.info(f"{'='*80}\n")

    def _check_exit(self, current_price: float):
        """Vérifie si doit sortir de la position"""

        if not self.current_position:
            return

        signal = self.current_position['signal']
        entry_price = self.current_position['entry_price']

        # Calculer PnL
        if signal.side == 'LONG':
            pnl_pct = (current_price - entry_price) / entry_price
        else:  # SHORT
            pnl_pct = (entry_price - current_price) / entry_price

        pnl_pct_leveraged = pnl_pct * signal.leverage * 100

        # Afficher position
        logger.info(f"📊 Position {signal.side} @ ${entry_price:,.2f}")
        logger.info(f"   Prix actuel: ${current_price:,.2f}")
        logger.info(f"   PnL: {pnl_pct_leveraged:+.1f}%")

        # Vérifier TP/SL
        should_close = False
        reason = ""

        if signal.side == 'LONG':
            if current_price >= signal.take_profit:
                should_close = True
                reason = "TP HIT"
            elif current_price <= signal.stop_loss:
                should_close = True
                reason = "SL HIT"
        else:  # SHORT
            if current_price <= signal.take_profit:
                should_close = True
                reason = "TP HIT"
            elif current_price >= signal.stop_loss:
                should_close = True
                reason = "SL HIT"

        if should_close:
            self._close_position(current_price, reason)

    def _close_position(self, exit_price: float, reason: str):
        """Ferme la position"""

        signal = self.current_position['signal']
        entry_price = self.current_position['entry_price']

        # Calculer PnL
        if signal.side == 'LONG':
            pnl_pct = (exit_price - entry_price) / entry_price
        else:
            pnl_pct = (entry_price - exit_price) / entry_price

        pnl_pct_leveraged = pnl_pct * signal.leverage * 100

        logger.info(f"\n{'='*80}")
        logger.info(f"🏁 FERMETURE POSITION - {reason}")
        logger.info(f"{'='*80}")
        logger.info(f"   {signal.side} @ Entry: ${entry_price:,.2f}")
        logger.info(f"   Exit: ${exit_price:,.2f}")
        logger.info(f"   PnL: {pnl_pct_leveraged:+.1f}%")

        # Stats
        self.stats['trades_closed'] += 1
        self.stats['total_pnl'] += pnl_pct_leveraged

        if pnl_pct_leveraged > 0:
            self.stats['wins'] += 1
            logger.info(f"   ✅ WIN")
        else:
            self.stats['losses'] += 1
            logger.info(f"   ❌ LOSS")

        logger.info(f"{'='*80}\n")

        # Fermer position réelle si mode LIVE
        if not self.dry_run and 'trade_hash' in self.current_position:
            trade_hash = self.current_position['trade_hash']
            logger.warning(f"   🚨 Fermeture position on-chain: {trade_hash}")

            success = self.client.close_position(trade_hash)

            if success:
                logger.info(f"   ✅ Position fermée on-chain!")
            else:
                logger.error(f"   ❌ Échec fermeture position on-chain!")

        # Clear position
        self.current_position = None

    def _print_stats(self):
        """Affiche les statistiques"""

        logger.info("\n" + "="*80)
        logger.info("📊 STATISTIQUES")
        logger.info("="*80)
        logger.info(f"   Signals vérifiés: {self.stats['signals_checked']}")
        logger.info(f"   Signals générés: {self.stats['signals_generated']}")
        logger.info(f"   Trades ouverts: {self.stats['trades_opened']}")
        logger.info(f"   Trades fermés: {self.stats['trades_closed']}")

        if self.stats['trades_closed'] > 0:
            win_rate = self.stats['wins'] / self.stats['trades_closed'] * 100
            logger.info(f"   Win rate: {win_rate:.1f}% ({self.stats['wins']}W / {self.stats['losses']}L)")
            logger.info(f"   PnL total: {self.stats['total_pnl']:+.1f}%")
            logger.info(f"   PnL moyen: {self.stats['total_pnl'] / self.stats['trades_closed']:+.1f}%")

        logger.info("="*80)


if __name__ == '__main__':
    import sys

    # Parse args
    dry_run = '--live' not in sys.argv

    if not dry_run:
        logger.warning("\n⚠️  MODE LIVE ACTIVÉ - Trading réel!")
        logger.warning("   Appuyez sur Ctrl+C dans les 5 secondes pour annuler...\n")
        time.sleep(5)

    # Launch
    bot = DegenScalpBot(dry_run=dry_run)
    bot.run(check_interval=30)  # Check toutes les 30s
