"""
ProfitTaker Worker - Gestion des fermetures de positions
Responsabilité : Fermer les positions selon différentes stratégies
"""

import logging
import time
from datetime import datetime, timedelta
from threading import Thread, Lock
from typing import Dict, List, Optional
import os
import json

# Import pour le cooldown
try:
    from cooldown_manager import CooldownManager
except ImportError:
    CooldownManager = None

class ProfitTaker:
    """Worker spécialisé dans la fermeture de positions"""

    def __init__(self, hyperliquid_client=None):
        self.hyperliquid_client = hyperliquid_client
        self.running = False

        # Cooldown manager partagé (optionnel)
        self.cooldown_manager = CooldownManager(default_cooldown_minutes=15) if CooldownManager else None

        # Storage des positions actives reconstruites
        self.active_positions = {}  # {symbol_side: PositionData}
        self.lock = Lock()

        # Configuration
        self.check_interval = 10  # Vérifier toutes les 10 secondes

        # Fichier de persistence des peaks
        self.peaks_file = "position_peaks.json"

        # Logger
        self.setup_logger()

        # Charger les peaks sauvegardés
        self.load_peaks()

        self.logger.info("=== PROFIT TAKER WORKER STARTED ===")

    def setup_logger(self):
        """Configure le système de logging"""
        self.logger = logging.getLogger("ProfitTaker")
        self.logger.setLevel(logging.INFO)

        # Créer le dossier logs si nécessaire
        logs_dir = "logs"
        if not os.path.exists(logs_dir):
            os.makedirs(logs_dir)

        # Handler fichier
        file_handler = logging.FileHandler(os.path.join(logs_dir, "profit_taker.log"))
        file_handler.setLevel(logging.INFO)

        # Handler console
        console_handler = logging.StreamHandler()
        console_handler.setLevel(logging.INFO)

        # Format
        formatter = logging.Formatter('%(asctime)s - [%(name)s] - %(message)s')
        file_handler.setFormatter(formatter)
        console_handler.setFormatter(formatter)

        # Fix encoding for file handler
        import codecs
        file_handler.stream = codecs.open(os.path.join(logs_dir, "profit_taker.log"), 'a', encoding='utf-8')

        if not self.logger.handlers:
            self.logger.addHandler(file_handler)
            self.logger.addHandler(console_handler)

    def load_peaks(self):
        """Charge les peaks sauvegardés depuis le fichier"""
        try:
            if os.path.exists(self.peaks_file):
                with open(self.peaks_file, 'r') as f:
                    self.saved_peaks = json.load(f)
                print(f"✅ Peaks restaurés: {len(self.saved_peaks)} positions sauvegardées")
            else:
                self.saved_peaks = {}
                print(f"ℹ️  Pas de peaks sauvegardés, démarrage fresh")
        except Exception as e:
            print(f"⚠️  Erreur chargement peaks: {e}")
            self.saved_peaks = {}

    def save_peaks(self):
        """Sauvegarde les peaks actuels dans le fichier (garde l'historique 6h)"""
        try:
            peaks_to_save = {}
            current_time = time.time()
            cutoff_time = current_time - (6 * 3600)  # 6 heures

            # Charger les peaks existants pour garder l'historique
            if os.path.exists(self.peaks_file):
                try:
                    with open(self.peaks_file, 'r') as f:
                        peaks_to_save = json.load(f)
                except:
                    peaks_to_save = {}

            # Nettoyer les peaks trop anciens (>6h)
            keys_to_remove = []
            for key, data in peaks_to_save.items():
                timestamp = data.get('timestamp', 0)
                if timestamp < cutoff_time:
                    keys_to_remove.append(key)

            for key in keys_to_remove:
                del peaks_to_save[key]

            # Ajouter/mettre à jour les peaks des positions actives
            with self.lock:
                for key, pos in self.active_positions.items():
                    peaks_to_save[key] = {
                        'peak_pnl_percent': pos.get('peak_pnl_percent', float('-inf')),
                        'symbol': pos['symbol'],
                        'side': pos['side'],
                        'entry_price': pos['entry_price'],
                        'timestamp': current_time
                    }

            with open(self.peaks_file, 'w') as f:
                json.dump(peaks_to_save, f, indent=2)
        except Exception as e:
            self.logger.error(f"Erreur sauvegarde peaks: {e}")

    def get_fills_from_hyperliquid(self, lookback_hours: int = 24) -> List[Dict]:
        """Récupère les fills depuis Hyperliquid"""
        if not self.hyperliquid_client:
            self.logger.warning("Client Hyperliquid non disponible")
            return []

        try:
            # Calculer la timestamp de début (lookback_hours heures en arrière)
            start_time = int((datetime.now() - timedelta(hours=lookback_hours)).timestamp() * 1000)

            #self.logger.info(f"Récupération des fills depuis {lookback_hours}h...")

            # Récupérer les fills depuis Hyperliquid
            all_fills = self.hyperliquid_client.get_fill_info(limit=1000)

            if not all_fills:
                self.logger.info("Aucun fill récupéré")
                return []

            # Filtrer par date
            filtered_fills = []
            for fill in all_fills:
                fill_time = int(fill.get('time', 0))
                if fill_time >= start_time:
                    filtered_fills.append(fill)

            self.logger.info(f"Récupérés {len(filtered_fills)}/{len(all_fills)} fills depuis {lookback_hours}h")
            return filtered_fills

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

    def get_current_positions_from_hyperliquid(self) -> List[Dict]:
        """Récupère les positions actuelles depuis Hyperliquid"""
        if not self.hyperliquid_client:
            return []

        try:
            positions = self.hyperliquid_client.get_positions()

            if positions:
                self.logger.info(f"Récupérées {len(positions)} positions actives depuis Hyperliquid")
                return positions
            else:
                self.logger.info("Aucune position active sur Hyperliquid")
                return []

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

    def reconstruct_trades_from_fills(self, fills: List[Dict]) -> Dict[str, Dict]:
        """Reconstitue les trades à partir des fills"""
        trades = {}

        for fill in fills:
            try:
                symbol = fill.get('coin', '').replace('-PERP', '')
                side = 'LONG' if fill.get('dir') == 'Open Long' or fill.get('dir') == 'Close Short' else 'SHORT'

                # Déterminer si c'est une ouverture ou fermeture
                direction = fill.get('dir', '')
                is_opening = 'Open' in direction

                size = abs(float(fill.get('sz', 0)))
                price = float(fill.get('px', 0))
                timestamp = int(fill.get('time', 0))

                trade_key = f"{symbol}_{side}"

                if trade_key not in trades:
                    trades[trade_key] = {
                        'symbol': symbol,
                        'side': side,
                        'opens': [],
                        'closes': [],
                        'total_opened': 0,
                        'total_closed': 0,
                        'avg_open_price': 0,
                        'current_size': 0
                    }

                if is_opening:
                    trades[trade_key]['opens'].append({
                        'size': size,
                        'price': price,
                        'time': timestamp
                    })
                    trades[trade_key]['total_opened'] += size
                else:
                    trades[trade_key]['closes'].append({
                        'size': size,
                        'price': price,
                        'time': timestamp
                    })
                    trades[trade_key]['total_closed'] += size

            except Exception as e:
                self.logger.error(f"Erreur traitement fill: {e}")
                continue

        # Calculer les prix moyens et tailles actuelles
        for trade_key, trade_data in trades.items():
            opens = trade_data['opens']
            if opens:
                total_value = sum(o['size'] * o['price'] for o in opens)
                total_size = sum(o['size'] for o in opens)
                trade_data['avg_open_price'] = total_value / total_size if total_size > 0 else 0
                trade_data['current_size'] = trade_data['total_opened'] - trade_data['total_closed']

        return trades

    def sync_with_current_positions(self, reconstructed_trades: Dict[str, Dict], current_positions: List[Dict]) -> Dict[str, Dict]:
        """
        NOUVELLE LOGIQUE: Partir directement des positions Hyperliquid pour éviter les décalages
        Les fills servent uniquement pour l'historique, pas pour déterminer les positions actives
        """
        active_positions = {}

        # PARTIR DIRECTEMENT DES POSITIONS HYPERLIQUID
        for pos in current_positions:
            # Adaptation selon le format des données (API directe vs get_positions)
            if 'position' in pos:
                # Format direct de l'API Hyperliquid
                position_info = pos.get('position', {})
                symbol = position_info.get('coin', '').replace('-PERP', '')
                szi = float(position_info.get('szi', 0))
                side = 'LONG' if szi > 0 else 'SHORT'
                size = abs(szi)
                entry_price = float(position_info.get('entryPx', 0))
                unrealized_pnl = float(pos.get('unrealizedPnl', 0))
            else:
                # Format de get_positions() déjà traité
                symbol = pos.get('symbol', '').replace('-PERP', '')
                side = pos.get('side', '').upper()
                size = abs(float(pos.get('size', 0)))
                entry_price = float(pos.get('entry_price', 0))
                unrealized_pnl = float(pos.get('unrealized_pnl', 0))

            # Filtrer les positions avec taille nulle (même logique que SimpleTradingEngine)
            if size <= 0.000001:
                continue

            key = f"{symbol}_{side}"

            # Récupérer l'historique des trades si disponible (optionnel)
            trade_data = reconstructed_trades.get(key, {
                'opens': [],
                'closes': [],
                'total_opened': size,
                'total_closed': 0
            })

            # Récupérer le prix de marché actuel
            current_market_price = 0
            try:
                if self.hyperliquid_client:
                    current_market_price = self.hyperliquid_client.get_current_market_price(symbol)
                    if not current_market_price:
                        current_market_price = float(pos.get('entry_price', 0))
            except:
                current_market_price = float(pos.get('entry_price', 0))

            # Récupération correcte du leverage selon le format des données
            if 'position' in pos:
                # Format API directe
                leverage_data = pos.get('position', {}).get('leverage', {})
            else:
                # Format get_positions()
                leverage_data = pos.get('leverage', {})

            leverage = leverage_data.get('value', 1) if isinstance(leverage_data, dict) else 1

            # Calculer un target price basé sur le leverage (similaire à pragmatic_signals)
            target_price = None
            if entry_price > 0:
                # Base TP% selon le leverage (mouvement de prix sans leverage)
                if leverage >= 10:
                    base_tp_percent = 0.4  # 0.4% de mouvement = 4% avec 10x
                elif leverage >= 5:
                    base_tp_percent = 0.6  # 0.6% de mouvement = 3% avec 5x
                elif leverage >= 3:
                    base_tp_percent = 1.0  # 1.0% de mouvement = 3% avec 3x
                else:
                    base_tp_percent = 1.5  # 1.5% de mouvement = 3% avec 2x

                if side == 'LONG':
                    target_price = entry_price * (1 + base_tp_percent / 100)
                else:  # SHORT
                    target_price = entry_price * (1 - base_tp_percent / 100)

            position_data = {
                'symbol': symbol,
                'side': side,
                'entry_price': entry_price,  # Utiliser la variable déjà définie
                'current_size': size,
                'current_price': current_market_price,
                'unrealized_pnl': unrealized_pnl,  # Utiliser la variable déjà définie
                'leverage': int(leverage),
                'target_price': target_price,  # Prix cible calculé
                'opens_history': trade_data.get('opens', []),
                'closes_history': trade_data.get('closes', []),
                'liquidation_price': pos.get('liquidation_px') if 'liquidation_px' in pos else pos.get('position', {}).get('liquidationPx'),
                'last_updated': datetime.now().isoformat(),
                'raw_hyperliquid_data': pos,
                'peak_pnl_percent': float('-inf')
            }

            # Calculer le PnL en utilisant la méthode centralisée d'HyperliquidClient
            if position_data['entry_price'] > 0 and position_data['current_price'] > 0:
                pnl_data = self.hyperliquid_client.calculate_position_pnl(
                    entry_price=position_data['entry_price'],
                    current_price=position_data['current_price'],
                    size=position_data['current_size'],
                    side=position_data['side'],
                    leverage=position_data['leverage']
                )
                position_data['pnl_percent'] = pnl_data['pnl_percent_leveraged']
                position_data['pnl_dollar'] = pnl_data['pnl_dollar']
            else:
                position_data['pnl_percent'] = 0
                position_data['pnl_dollar'] = 0

            # Calculer et mettre à jour le peakPNL (ne jamais l'écraser si inférieur)
            current_pnl = position_data['pnl_percent']

            # Récupérer l'ancien peakPNL si la position existe déjà
            existing_position = self.active_positions.get(key)

            # IMPORTANT: Réinitialiser le peak si c'est une nouvelle position
            if not existing_position or existing_position.get('current_size', 0) == 0:
                # Vérifier s'il existe un peak sauvegardé pour cette position
                saved_peak_data = self.saved_peaks.get(key, {})
                saved_peak = saved_peak_data.get('peak_pnl_percent', float('-inf'))
                saved_entry = saved_peak_data.get('entry_price', 0)

                # Utiliser le peak sauvegardé seulement si c'est la MÊME position (même entry price)
                if saved_entry > 0 and abs(saved_entry - position_data['entry_price']) < 0.01:
                    previous_peak = saved_peak
                    self.logger.info(f"Position {key} - Peak restauré depuis sauvegarde: {saved_peak:.2f}%")
                else:
                    previous_peak = float('-inf')
                    self.logger.info(f"Nouvelle position détectée pour {key} - Peak réinitialisé")
            else:
                previous_peak = existing_position.get('peak_pnl_percent', float('-inf'))

            # Mettre à jour le peakPNL
            position_data['peak_pnl_percent'] = max(previous_peak, current_pnl)

            active_positions[key] = position_data

        return active_positions

    def update_active_positions(self):
        """Met à jour le repo des positions actives"""
        try:
            #self.logger.info("Mise à jour des positions actives...")

            # 1. Récupérer les fills récents
            fills = self.get_fills_from_hyperliquid(lookback_hours=72)  # 3 jours de lookback

            # 2. Récupérer les positions actuelles
            current_positions = self.get_current_positions_from_hyperliquid()

            # 3. Reconstituer les trades
            reconstructed_trades = self.reconstruct_trades_from_fills(fills)
            self.logger.info(f"Reconstruits {len(reconstructed_trades)} trades depuis les fills")

            # 4. Synchroniser avec les positions actuelles
            active_positions = self.sync_with_current_positions(reconstructed_trades, current_positions)

            # 5. Mettre à jour le storage thread-safe
            with self.lock:
                self.active_positions = active_positions

            self.logger.info(f"Positions actives mises à jour: {len(active_positions)}")

            # Log clair et détaillé des positions
            if active_positions:
                self.logger.info("=" * 80)
                self.logger.info("POSITIONS ACTIVES:")
                self.logger.info("=" * 80)
                for key, pos in active_positions.items():
                    symbol = pos['symbol']
                    side = pos['side']
                    entry = pos['entry_price']
                    current = pos['current_price']
                    size = pos['current_size']
                    pnl_pct = pos['pnl_percent']
                    peak_pnl = pos['peak_pnl_percent']
                    leverage = pos['leverage']

                    # Formatage propre selon la taille du nombre
                    if entry >= 1000:
                        entry_str = f"${entry:,.2f}"
                        current_str = f"${current:,.2f}"
                    else:
                        entry_str = f"${entry:.5f}"
                        current_str = f"${current:.5f}"

                    pnl_sign = "+" if pnl_pct >= 0 else ""
                    pnl_color = "UP" if pnl_pct >= 0 else "DOWN"

                    # Gestion de l'affichage du peak (éviter -inf)
                    if peak_pnl == float('-inf'):
                        peak_display = "  N/A  "
                    else:
                        peak_sign = "+" if peak_pnl >= 0 else ""
                        peak_display = f"{peak_sign}{peak_pnl:>6.2f}%"

                    self.logger.info(f"{symbol:<6} {side:<5} | Entry: {entry_str:<12} -> Current: {current_str:<12} | "
                                   f"Size: {size:<8.3f} | Leverage: {leverage:>2}x | "
                                   f"PnL: {pnl_sign}{pnl_pct:>6.2f}% | Peak: {peak_display} {pnl_color}")

                self.logger.info("=" * 80)
            else:
                self.logger.info("Aucune position active détectée")

        except Exception as e:
            self.logger.error(f"Erreur mise à jour positions: {e}")

    def close_position_by_symbol(self, symbol: str, reason: str = "STOP_LOSS") -> Dict:
        """Ferme une position par symbole via le client Hyperliquid"""
        try:
            if not self.hyperliquid_client:
                return {"success": False, "error": "Client Hyperliquid non disponible"}

            # Récupérer les positions actuelles
            hl_positions = self.hyperliquid_client.get_positions()
            target_position = None

            # Chercher la position par symbole
            for pos in hl_positions:
                pos_symbol = pos.get('symbol', '').replace('-PERP', '')
                if pos_symbol == symbol and float(pos.get('size', 0)) != 0:
                    target_position = pos
                    break

            if not target_position:
                return {"success": False, "error": f"Position {symbol} non trouvée"}

            # Déterminer le côté de fermeture (opposé à la position)
            position_side = target_position.get('side', '').upper()
            is_buy = (position_side == 'SHORT')  # Pour fermer SHORT on achète, pour fermer LONG on vend
            size = abs(float(target_position.get('size', 0)))

            self.logger.info(f"Fermeture position {symbol} {position_side}: Size={size}, Reason={reason}")

            # Placer l'ordre de fermeture
            result = self.hyperliquid_client.place_market_order(
                symbol=symbol,
                is_buy=is_buy,
                size=size,
                reduce_only=True,
                order_tag=f"CLOSE_{reason}_{symbol}"
            )

            if result.get('success'):
                self.logger.info(f"Position {symbol} fermée avec succès: {reason}")

                # Enregistrer la fermeture dans le cooldown manager
                if self.cooldown_manager:
                    self.cooldown_manager.record_position_close(symbol, reason)

                # Supprimer le peak sauvegardé de cette position
                with self.lock:
                    for key in list(self.active_positions.keys()):
                        if self.active_positions[key]['symbol'] == symbol:
                            if key in self.saved_peaks:
                                del self.saved_peaks[key]
                self.save_peaks()  # Sauvegarder immédiatement

                return {"success": True, "message": f"Position {symbol} fermée"}
            else:
                self.logger.error(f"Échec fermeture {symbol}: {result.get('error')}")
                return {"success": False, "error": result.get('error', 'Erreur inconnue')}

        except Exception as e:
            error_msg = f"Erreur fermeture position {symbol}: {e}"
            self.logger.error(error_msg)
            return {"success": False, "error": error_msg}

    def check_stop_loss_conditions_old_version(self):
        """ANCIENNE VERSION -12% - REMPLACÉE PAR VERSION ADAPTATIVE - NE PAS UTILISER"""
        # Cette fonction a été désactivée car elle écrasait la version adaptative selon leverage
        # La bonne version est plus bas avec seuils -4/-5/-6/-8 selon leverage
        pass

    def check_target_price_conditions(self):
        """Vérifie si les positions ont atteint leur target price (TP)"""
        with self.lock:
            positions_to_close = []

            for key, position in self.active_positions.items():
                symbol = position['symbol']
                side = position['side']
                current_price = position.get('current_price', 0)
                target_price = position.get('target_price')
                current_pnl = position['pnl_percent']

                # TARGET PRICE COMPLÈTEMENT DÉSACTIVÉ
                # Seul le trailing stop gère les fermetures pour capturer les gros gains
                if target_price:
                    self.logger.debug(f"TARGET PRICE DISABLED: {symbol} géré uniquement par trailing stop (PnL: {current_pnl:.2f}%)")

        # Fermer les positions en dehors du lock
        for symbol, reason in positions_to_close:
            try:
                result = self.close_position_by_symbol(symbol, reason)
                if result.get('success'):
                    self.logger.critical(f"TARGET PRICE EXECUTED: {symbol} fermée avec succès sur TP")
                else:
                    self.logger.error(f"TARGET PRICE FAILED: {symbol} - {result.get('error')}")
            except Exception as e:
                self.logger.error(f"Erreur target price {symbol}: {e}")

    def check_small_position_conditions(self):
        """Vérifie et ferme les positions trop petites"""
        # Configuration des seuils
        MIN_POSITION_VALUE_USD = 10.0  # Valeur minimum en USD pour garder une position (ajusté pour tailles ~$25)

        with self.lock:
            positions_to_close = []

            for key, position in self.active_positions.items():
                symbol = position['symbol']
                current_size = position['current_size']
                current_price = position.get('current_price', 0)

                # Calculer la valeur de la position en USD
                position_value_usd = current_size * current_price

                # Vérifier si la position est trop petite
                if position_value_usd > 0 and position_value_usd < MIN_POSITION_VALUE_USD:
                    self.logger.warning(f"SMALL POSITION DETECTED: {symbol} Value=${position_value_usd:.2f} < ${MIN_POSITION_VALUE_USD} (Size={current_size:.3f} @ ${current_price:.4f})")
                    positions_to_close.append((symbol, position_value_usd))

        # Fermer les positions trop petites en dehors du lock
        for symbol, value in positions_to_close:
            try:
                result = self.close_position_by_symbol(symbol, f"SMALL_POSITION_${value:.1f}")
                if result.get('success'):
                    self.logger.critical(f"SMALL POSITION CLOSED: {symbol} fermée avec succès (Value=${value:.2f})")
                else:
                    self.logger.error(f"SMALL POSITION CLOSE FAILED: {symbol} - {result.get('error')}")
            except Exception as e:
                self.logger.error(f"Erreur fermeture petite position {symbol}: {e}")

    def check_trailing_stop_conditions(self):
        """Vérifie les conditions de trailing stop adaptatif selon le leverage"""
        with self.lock:
            positions_to_close = []

            for key, position in self.active_positions.items():
                current_pnl = position['pnl_percent']
                peak_pnl = position['peak_pnl_percent']
                symbol = position['symbol']
                leverage = position.get('leverage', 1)

                # TRAILING STOP SIMPLIFIÉ ET EFFICACE
                # Activation dès +2% de profit, distance fixe de 8%
                # Plus le peak est haut, plus on tolère de recul

                min_profit_activation = 2.0  # Trailing activé dès +2% de profit

                # Distance trailing RESSERRÉE - on garde plus de profit!
                if peak_pnl >= 20.0:
                    trailing_distance = 6.0   # Peak > 20%: 6% de recul max
                elif peak_pnl >= 10.0:
                    trailing_distance = 4.0   # Peak 10-20%: 4% de recul
                elif peak_pnl >= 5.0:
                    trailing_distance = 3.0   # Peak 5-10%: 3% de recul
                else:
                    trailing_distance = 2.0   # Peak 2-5%: 2% de recul seulement

                # Conditions pour le trailing stop:
                # 1. Peak a atteint au moins +2%
                # 2. On a reculé de trailing_distance depuis le peak
                if (peak_pnl != float('-inf') and
                    peak_pnl >= min_profit_activation and
                    current_pnl <= (peak_pnl - trailing_distance)):

                    drawdown = peak_pnl - current_pnl
                    self.logger.warning(f"🔻 TRAILING STOP: {symbol} L{leverage}x | PnL={current_pnl:.2f}% | Peak={peak_pnl:.2f}% | Recul={drawdown:.2f}% > {trailing_distance:.0f}%")
                    positions_to_close.append((symbol, leverage))

        # Fermer les positions en dehors du lock
        for symbol, leverage in positions_to_close:
            try:
                result = self.close_position_by_symbol(symbol, f"TRAILING_STOP_LEV{leverage}x")
                if result.get('success'):
                    self.logger.critical(f"TRAILING STOP EXECUTED: {symbol} fermée avec succès (Leverage {leverage}x)")
                    # Enregistrer cooldown
                    if self.cooldown_manager:
                        self.cooldown_manager.record_position_close(symbol, "TRAILING_STOP")
                else:
                    self.logger.error(f"TRAILING STOP FAILED: {symbol} - {result.get('error')}")
            except Exception as e:
                self.logger.error(f"Erreur trailing stop {symbol}: {e}")

    def check_trend_reversal_conditions(self):
        """Détecte les véritables inversions de tendance basées sur des signaux contraires"""
        with self.lock:
            positions_to_close = []

            for key, position in self.active_positions.items():
                symbol = position['symbol']
                side = position['side']
                pnl = position['pnl_percent']
                leverage = position.get('leverage', 1)

                # VRAI TREND REVERSAL : Vérifier signal contraire fort
                reversal_detected = self._detect_real_trend_reversal(symbol, side, pnl)

                if reversal_detected:
                    self.logger.warning(f"REAL TREND REVERSAL DETECTED: {symbol} {side} | Strong opposite signal detected | PnL={pnl:.2f}%")
                    positions_to_close.append((symbol, side, pnl, leverage))

        # Fermer complètement les positions avec vraie inversion
        for symbol, side, pnl, leverage in positions_to_close:
            try:
                reason = f"REAL_TREND_REVERSAL_{side}_L{leverage}x_{pnl:.1f}%"
                result = self.close_position_by_symbol(symbol, reason)
                if result.get('success'):
                    self.logger.critical(f"REAL TREND REVERSAL CLOSE: {symbol} {side} fermée complètement (PnL={pnl:.2f}%)")
                    # Enregistrer cooldown
                    if self.cooldown_manager:
                        self.cooldown_manager.record_position_close(symbol, "TREND_REVERSAL")
                else:
                    self.logger.error(f"REAL TREND REVERSAL CLOSE FAILED: {symbol} - {result.get('error')}")
            except Exception as e:
                self.logger.error(f"Erreur fermeture vraie inversion {symbol}: {e}")

    def _detect_real_trend_reversal(self, symbol: str, current_side: str, pnl: float) -> bool:
        """
        Détecte un vrai retournement de tendance basé sur des signaux contraires
        Returns True si un signal contraire fort est détecté
        """
        try:
            # Importer le moteur de signaux pour analyser la tendance actuelle
            from simple_trading_system.pragmatic_signals import PragmaticSignalGenerator

            # Créer une instance temporaire du générateur de signaux
            signal_gen = PragmaticSignalGenerator()

            # Générer tous les signaux et filtrer pour ce symbole
            all_signals = signal_gen.generate_signals()
            signal = None
            for sig in all_signals:
                if sig.get('symbol') == symbol:
                    signal = sig
                    break

            if not signal:
                return False

            # Vérifier si le nouveau signal est contraire à notre position
            signal_side = signal.get('side', '')
            signal_confidence = signal.get('confidence', 0)

            # Conditions pour un vrai retournement :
            # 1. Signal contraire avec forte confiance (>80%)
            # 2. OU perte importante (>-3%) avec signal contraire modéré (>60%)
            is_opposite_signal = (current_side == 'LONG' and signal_side == 'SHORT') or \
                               (current_side == 'SHORT' and signal_side == 'LONG')

            if is_opposite_signal:
                if signal_confidence >= 80.0:
                    self.logger.info(f"Strong opposite signal: {symbol} {current_side} -> {signal_side} signal at {signal_confidence:.1f}% confidence")
                    return True
                elif signal_confidence >= 60.0 and pnl <= -3.0:
                    self.logger.info(f"Moderate opposite signal with loss: {symbol} {current_side} -> {signal_side} signal at {signal_confidence:.1f}% confidence, PnL={pnl:.2f}%")
                    return True

            return False

        except Exception as e:
            self.logger.error(f"Erreur détection vraie inversion {symbol}: {e}")
            return False

    def check_stop_loss_conditions(self):
        """Système de stop-loss séparé du trend reversal - moins agressif"""
        with self.lock:
            positions_to_close = []

            for key, position in self.active_positions.items():
                symbol = position['symbol']
                side = position['side']
                pnl = position['pnl_percent']
                leverage = position.get('leverage', 1)

                # Stop-loss selon le leverage - ASSOUPLI pour laisser respirer les positions
                # Nouveau ratio : ~50% de perte en capital max (au lieu de 32%)
                if leverage >= 8:
                    stop_loss_threshold = -6.0  # -6% pour high leverage (perte cap ~48%)
                elif leverage >= 5:
                    stop_loss_threshold = -8.0  # -8% pour leverage moyen (perte cap ~40%)
                elif leverage >= 3:
                    stop_loss_threshold = -12.0 # -12% pour leverage faible (perte cap ~36%)
                else:
                    stop_loss_threshold = -15.0 # -15% pour très faible leverage

                # Stop-loss déclenché seulement en cas de grosse perte
                if pnl <= stop_loss_threshold:
                    self.logger.warning(f"STOP LOSS TRIGGERED: {symbol} {side} | PnL={pnl:.2f}% | Leverage={leverage}x | Threshold={stop_loss_threshold}%")
                    positions_to_close.append((symbol, side, pnl, leverage))

        # Fermer les positions avec stop-loss
        for symbol, side, pnl, leverage in positions_to_close:
            try:
                reason = f"STOP_LOSS_{side}_L{leverage}x_{pnl:.1f}%"
                result = self.close_position_by_symbol(symbol, reason)
                if result.get('success'):
                    self.logger.critical(f"STOP LOSS CLOSE: {symbol} {side} fermée complètement (PnL={pnl:.2f}%)")
                    # Enregistrer cooldown
                    if self.cooldown_manager:
                        self.cooldown_manager.record_position_close(symbol, "STOP_LOSS")
                else:
                    self.logger.error(f"STOP LOSS CLOSE FAILED: {symbol} - {result.get('error')}")
            except Exception as e:
                self.logger.error(f"Erreur fermeture stop-loss {symbol}: {e}")

    def profit_taker_loop(self):
        """Boucle principale du ProfitTaker"""
        self.logger.info("Démarrage de la boucle ProfitTaker...")

        while self.running:
            try:
                # Mettre à jour les positions actives
                self.update_active_positions()

                # Vérifier les conditions de stop loss
                self.check_stop_loss_conditions()

                # Vérifier les conditions de target price (TP)
                self.check_target_price_conditions()

                # NOUVEAU: Vérifier les vraies inversions de tendance (signaux contraires)
                self.check_trend_reversal_conditions()

                # NOUVEAU: Vérifier les stop-loss (protection des pertes importantes)
                self.check_stop_loss_conditions()

                # Vérifier et fermer les positions trop petites
                self.check_small_position_conditions()

                # Vérifier les conditions de trailing stop
                self.check_trailing_stop_conditions()

                # Sauvegarder les peaks toutes les 30 secondes (3 cycles)
                if not hasattr(self, '_last_peak_save'):
                    self._last_peak_save = 0
                if time.time() - self._last_peak_save > 30:
                    self.save_peaks()
                    self._last_peak_save = time.time()

                # Pause avant la prochaine itération
                time.sleep(self.check_interval)

            except Exception as e:
                self.logger.error(f"Erreur dans profit_taker_loop: {e}")
                time.sleep(5)

    def start(self):
        """Démarre le ProfitTaker"""
        if not self.running:
            self.running = True
            self.worker_thread = Thread(target=self.profit_taker_loop)
            self.worker_thread.daemon = True
            self.worker_thread.start()
            self.logger.info("ProfitTaker démarré")

    def stop(self):
        """Arrête le ProfitTaker"""
        self.running = False
        if hasattr(self, 'worker_thread'):
            self.worker_thread.join(timeout=5)
        self.logger.info("ProfitTaker arrêté")

    def get_positions_summary(self) -> Dict:
        """Retourne un résumé des positions actives"""
        with self.lock:
            return {
                'total_positions': len(self.active_positions),
                'positions': {key: {
                    'symbol': pos['symbol'],
                    'side': pos['side'],
                    'pnl_percent': pos['pnl_percent'],
                    'current_size': pos['current_size']
                } for key, pos in self.active_positions.items()}
            }