#!/usr/bin/env python3
"""
═══════════════════════════════════════════════════════════════
📊 LOG ANALYZER - ICHIGRIDEA PIPELINE
═══════════════════════════════════════════════════════════════
Analyse les logs de trading pour détecter patterns et anomalies

Usage:
    python log_analyzer.py <logfile> [--errors] [--stats] [--report]
"""

import re
import sys
import json
from collections import Counter, defaultdict
from datetime import datetime
from pathlib import Path
from typing import List, Dict, Tuple


class LogAnalyzer:
    """Analyseur de logs IchiGridEA"""
    
    # Patterns de log
    PATTERNS = {
        'error': re.compile(r'\[ERROR\]|\[CRITICAL\]|failed|error', re.IGNORECASE),
        'warning': re.compile(r'\[WARNING\]|\[WARN\]|warning', re.IGNORECASE),
        'trade': re.compile(r'(BUY|SELL|CLOSE)\s+.+?(ticket|order)', re.IGNORECASE),
        'signal': re.compile(r'\[SIGNAL\]|Signal:\s*(BUY|SELL|NONE)', re.IGNORECASE),
        'grid': re.compile(r'\[GRID\]|Grid level|GridLevel', re.IGNORECASE),
        'protection': re.compile(r'\[PROTECTION\]|Drawdown|Emergency', re.IGNORECASE),
        'debug': re.compile(r'\[DEBUG\]', re.IGNORECASE),
        'timestamp': re.compile(r'(\d{4}\.\d{2}\.\d{2}\s+\d{2}:\d{2}:\d{2})'),
    }
    
    def __init__(self, log_path: str):
        self.log_path = Path(log_path)
        self.lines: List[str] = []
        self.errors: List[Tuple[int, str]] = []
        self.warnings: List[Tuple[int, str]] = []
        self.trades: List[Dict] = []
        self.signals: List[Dict] = []
        self.stats: Dict = defaultdict(int)
        
    def load(self) -> bool:
        """Charge le fichier de log"""
        try:
            with open(self.log_path, 'r', encoding='utf-8', errors='ignore') as f:
                self.lines = f.readlines()
            print(f"✅ Chargé: {len(self.lines)} lignes")
            return True
        except Exception as e:
            print(f"❌ Erreur de chargement: {e}")
            return False
    
    def analyze(self):
        """Analyse complète du log"""
        print("🔍 Analyse en cours...")
        
        for i, line in enumerate(self.lines, 1):
            # Compter les types
            if self.PATTERNS['error'].search(line):
                self.errors.append((i, line.strip()))
                self.stats['errors'] += 1
            elif self.PATTERNS['warning'].search(line):
                self.warnings.append((i, line.strip()))
                self.stats['warnings'] += 1
            
            if self.PATTERNS['trade'].search(line):
                self.stats['trades'] += 1
                self._parse_trade(i, line)
            
            if self.PATTERNS['signal'].search(line):
                self.stats['signals'] += 1
            
            if self.PATTERNS['grid'].search(line):
                self.stats['grid_events'] += 1
            
            if self.PATTERNS['protection'].search(line):
                self.stats['protection_events'] += 1
            
            if self.PATTERNS['debug'].search(line):
                self.stats['debug'] += 1
        
        self.stats['total_lines'] = len(self.lines)
        
    def _parse_trade(self, line_num: int, line: str):
        """Parse une ligne de trade"""
        # Extraire les infos basiques
        trade_info = {
            'line': line_num,
            'raw': line.strip(),
            'type': 'BUY' if 'BUY' in line.upper() else 'SELL' if 'SELL' in line.upper() else 'CLOSE',
        }
        
        # Extraire le ticket si présent
        ticket_match = re.search(r'ticket[:\s]*(\d+)', line, re.IGNORECASE)
        if ticket_match:
            trade_info['ticket'] = int(ticket_match.group(1))
        
        # Extraire le lot si présent
        lot_match = re.search(r'(\d+\.?\d*)\s*lots?', line, re.IGNORECASE)
        if lot_match:
            trade_info['lots'] = float(lot_match.group(1))
        
        self.trades.append(trade_info)
    
    def get_error_summary(self) -> Dict:
        """Résumé des erreurs"""
        error_types = Counter()
        for _, line in self.errors:
            # Extraire le type d'erreur
            match = re.search(r'\[(\w+)\]', line)
            if match:
                error_types[match.group(1)] += 1
            else:
                error_types['UNKNOWN'] += 1
        
        return {
            'total': len(self.errors),
            'types': dict(error_types),
            'first_10': self.errors[:10]
        }
    
    def get_trading_stats(self) -> Dict:
        """Statistiques de trading"""
        buy_count = sum(1 for t in self.trades if t['type'] == 'BUY')
        sell_count = sum(1 for t in self.trades if t['type'] == 'SELL')
        close_count = sum(1 for t in self.trades if t['type'] == 'CLOSE')
        
        return {
            'total_trades': len(self.trades),
            'buys': buy_count,
            'sells': sell_count,
            'closes': close_count,
            'ratio': f"{buy_count}:{sell_count}" if sell_count > 0 else "N/A"
        }
    
    def detect_anomalies(self) -> List[Dict]:
        """Détecte les anomalies potentielles"""
        anomalies = []
        
        # 1. Trop d'erreurs consécutives
        error_streak = 0
        for i, line in enumerate(self.lines):
            if self.PATTERNS['error'].search(line):
                error_streak += 1
                if error_streak >= 5:
                    anomalies.append({
                        'type': 'ERROR_STREAK',
                        'line': i + 1,
                        'message': f'5+ erreurs consécutives détectées'
                    })
                    error_streak = 0
            else:
                error_streak = 0
        
        # 2. Protection events élevés
        if self.stats['protection_events'] > 10:
            anomalies.append({
                'type': 'HIGH_PROTECTION',
                'count': self.stats['protection_events'],
                'message': 'Nombreux événements de protection'
            })
        
        # 3. Ratio erreurs/lignes
        error_ratio = self.stats['errors'] / max(1, self.stats['total_lines'])
        if error_ratio > 0.05:  # Plus de 5% d'erreurs
            anomalies.append({
                'type': 'HIGH_ERROR_RATE',
                'ratio': f'{error_ratio:.1%}',
                'message': 'Taux d\'erreurs élevé'
            })
        
        return anomalies
    
    def generate_report(self) -> str:
        """Génère un rapport markdown"""
        report = f"""# 📊 Rapport d'Analyse de Log

**Fichier**: {self.log_path.name}
**Date d'analyse**: {datetime.now().isoformat()}
**Lignes totales**: {self.stats['total_lines']}

## Résumé

| Métrique | Valeur |
|----------|--------|
| Erreurs | {self.stats['errors']} |
| Warnings | {self.stats['warnings']} |
| Trades | {self.stats['trades']} |
| Signaux | {self.stats['signals']} |
| Grid Events | {self.stats['grid_events']} |
| Protection Events | {self.stats['protection_events']} |

## Erreurs Détaillées

"""
        error_summary = self.get_error_summary()
        report += f"**Total erreurs**: {error_summary['total']}\n\n"
        
        if error_summary['types']:
            report += "### Par type\n\n"
            for error_type, count in error_summary['types'].items():
                report += f"- {error_type}: {count}\n"
        
        if error_summary['first_10']:
            report += "\n### Premières erreurs\n\n```\n"
            for line_num, line in error_summary['first_10']:
                report += f"L{line_num}: {line[:100]}...\n"
            report += "```\n"
        
        # Anomalies
        anomalies = self.detect_anomalies()
        if anomalies:
            report += "\n## ⚠️ Anomalies Détectées\n\n"
            for anomaly in anomalies:
                report += f"- **{anomaly['type']}**: {anomaly['message']}\n"
        
        # Stats trading
        trading_stats = self.get_trading_stats()
        report += f"""
## Statistiques Trading

- Total trades: {trading_stats['total_trades']}
- Buys: {trading_stats['buys']}
- Sells: {trading_stats['sells']}
- Closes: {trading_stats['closes']}
- Ratio Buy/Sell: {trading_stats['ratio']}
"""
        
        return report
    
    def print_summary(self):
        """Affiche un résumé console"""
        print("\n" + "="*60)
        print("📊 RÉSUMÉ D'ANALYSE")
        print("="*60)
        print(f"Fichier: {self.log_path.name}")
        print(f"Lignes: {self.stats['total_lines']}")
        print(f"Erreurs: {self.stats['errors']}")
        print(f"Warnings: {self.stats['warnings']}")
        print(f"Trades: {self.stats['trades']}")
        print(f"Signaux: {self.stats['signals']}")
        print("="*60)


def main():
    if len(sys.argv) < 2:
        print(__doc__)
        print("\nUsage: python log_analyzer.py <logfile> [options]")
        print("Options:")
        print("  --errors   Afficher les erreurs détaillées")
        print("  --stats    Afficher les statistiques")
        print("  --report   Générer un rapport markdown")
        sys.exit(1)
    
    log_path = sys.argv[1]
    analyzer = LogAnalyzer(log_path)
    
    if not analyzer.load():
        sys.exit(1)
    
    analyzer.analyze()
    
    if "--errors" in sys.argv:
        print("\n❌ ERREURS:")
        for line_num, line in analyzer.errors[:20]:
            print(f"  L{line_num}: {line[:80]}...")
    
    if "--stats" in sys.argv:
        analyzer.print_summary()
        
        trading_stats = analyzer.get_trading_stats()
        print(f"\n📈 Trading: {trading_stats}")
        
        anomalies = analyzer.detect_anomalies()
        if anomalies:
            print("\n⚠️ Anomalies:")
            for a in anomalies:
                print(f"  - {a['type']}: {a['message']}")
    
    if "--report" in sys.argv:
        report = analyzer.generate_report()
        
        # Sauvegarder le rapport
        report_path = Path(log_path).stem + "_analysis.md"
        with open(report_path, 'w') as f:
            f.write(report)
        print(f"\n📄 Rapport sauvegardé: {report_path}")
    
    if len(sys.argv) == 2:
        # Par défaut, afficher le résumé
        analyzer.print_summary()


if __name__ == "__main__":
    main()
