#!/usr/bin/env python3
"""
AI-GENERATOR MIT MUSTER-GEWICHTUNG
Erweitert den AI-Generator um explizite Muster-Gewichtung (NNMMHH, etc.)

Neue Features:
- Historische Muster-Analyse (NNMMHH, NMMHHH, etc.)
- Muster-Erfolgsquoten berechnen
- Muster-basierte Tip-Optimierung  
- Pattern-Scoring für bessere Kombinationen
"""

import pandas as pd
import numpy as np
from collections import Counter, defaultdict
import random

class PatternWeightedAI:
    def __init__(self, df):
        self.df = df
        self.pattern_frequencies = Counter()
        self.pattern_success_rates = {}
        self.optimal_patterns = []
        
        # Analysiere historische Muster
        self._analyze_historical_patterns()
    
    def _analyze_historical_patterns(self):
        """Analysiert alle historischen Muster und deren Erfolgsquoten."""
        print("\n🎨 MUSTER-ANALYSE GESTARTET...")
        
        if len(self.df) == 0:
            return
        
        total_drawings = len(self.df)
        
        for _, row in self.df.iterrows():
            numbers = sorted([row['Z1'], row['Z2'], row['Z3'], row['Z4'], row['Z5'], row['Z6']])
            pattern = self._get_pattern(numbers)
            self.pattern_frequencies[pattern] += 1
        
        # Berechne Erfolgsquoten
        for pattern, count in self.pattern_frequencies.items():
            success_rate = count / total_drawings
            self.pattern_success_rates[pattern] = success_rate
        
        # Identifiziere optimale Muster (Top 10)
        self.optimal_patterns = [
            pattern for pattern, _ in self.pattern_frequencies.most_common(10)
        ]
        
        print("🎯 MUSTER-ERFOLGSQUOTEN:")
        print("Pattern    Häufigkeit  Erfolgsrate  Bewertung")
        print("-" * 50)
        
        for i, (pattern, count) in enumerate(self.pattern_frequencies.most_common(15)):
            success_rate = self.pattern_success_rates[pattern]
            
            if success_rate >= 0.08:
                bewertung = "🏆 EXCELLENT"
            elif success_rate >= 0.06:
                bewertung = "🥇 SEHR GUT"
            elif success_rate >= 0.04:
                bewertung = "🥈 GUT"
            elif success_rate >= 0.02:
                bewertung = "🥉 DURCHSCHNITT"
            else:
                bewertung = "❌ SCHWACH"
            
            print(f"{pattern:<10} {count:>8}    {success_rate:>8.3f}    {bewertung}")
    
    def _get_pattern(self, numbers):
        """Konvertiert Zahlen zu N/M/H Muster."""
        pattern = ""
        for num in numbers:
            if 1 <= num <= 16:
                pattern += "N"  # Niedrig
            elif 17 <= num <= 32:
                pattern += "M"  # Mittel  
            else:
                pattern += "H"  # Hoch
        return pattern
    
    def calculate_pattern_weight(self, numbers):
        """Berechnet Gewichtung basierend auf Muster-Erfolgsquote."""
        pattern = self._get_pattern(sorted(numbers))
        
        # Basis-Gewichtung aus historischer Erfolgsquote
        base_weight = self.pattern_success_rates.get(pattern, 0.01)
        
        # Bonus für Top-Muster
        if pattern in self.optimal_patterns[:5]:
            bonus = 0.3
        elif pattern in self.optimal_patterns[:10]:
            bonus = 0.2
        else:
            bonus = 0.0
        
        # Penalty für nie aufgetretene Muster
        if pattern not in self.pattern_frequencies:
            penalty = -0.2
        else:
            penalty = 0.0
        
        final_weight = base_weight + bonus + penalty
        return max(0.01, min(1.0, final_weight))  # Clamp 0.01-1.0
    
    def get_pattern_recommendations(self):
        """Liefert Muster-Empfehlungen für Tip-Generierung."""
        recommendations = {}
        
        # Top 5 erfolgreichste Muster
        recommendations['top_patterns'] = self.optimal_patterns[:5]
        
        # Muster mit bester Erfolgsquote
        if self.pattern_success_rates:
            best_pattern = max(self.pattern_success_rates.items(), key=lambda x: x[1])
            recommendations['best_pattern'] = best_pattern[0]
            recommendations['best_success_rate'] = best_pattern[1]
        
        # Muster-Statistiken
        recommendations['total_patterns'] = len(self.pattern_frequencies)
        recommendations['pattern_diversity'] = len([p for p, rate in self.pattern_success_rates.items() if rate >= 0.02])
        
        return recommendations
    
    def optimize_combination_for_pattern(self, target_pattern="NNMMHH"):
        """Optimiert Zahlen-Kombination für spezifisches Muster."""
        
        # Definiere Bereiche
        ranges = {
            'N': list(range(1, 17)),   # Niedrig: 1-16
            'M': list(range(17, 33)),  # Mittel: 17-32
            'H': list(range(33, 50))   # Hoch: 33-49
        }
        
        # Parse target pattern
        pattern_counts = Counter(target_pattern)
        needed_n = pattern_counts.get('N', 0)
        needed_m = pattern_counts.get('M', 0) 
        needed_h = pattern_counts.get('H', 0)
        
        selected = []
        
        # Wähle Zahlen für Muster
        if needed_n > 0:
            n_numbers = random.sample(ranges['N'], min(needed_n, len(ranges['N'])))
            selected.extend(n_numbers)
        
        if needed_m > 0:
            m_numbers = random.sample(ranges['M'], min(needed_m, len(ranges['M'])))
            selected.extend(m_numbers)
        
        if needed_h > 0:
            h_numbers = random.sample(ranges['H'], min(needed_h, len(ranges['H'])))
            selected.extend(h_numbers)
        
        # Auffüllen falls nötig
        while len(selected) < 6:
            all_ranges = ranges['N'] + ranges['M'] + ranges['H']
            available = [n for n in all_ranges if n not in selected]
            if available:
                selected.append(random.choice(available))
            else:
                break
        
        return sorted(selected[:6])

class EnhancedAIGenerator:
    """Erweitert den ursprünglichen AI-Generator um Muster-Gewichtung."""
    
    def __init__(self, data_path):
        self.data_path = data_path
        self.df = None
        self.pattern_ai = None
        
        # Load data
        self._load_data()
        
        # Initialize Pattern AI
        if self.df is not None and len(self.df) > 0:
            self.pattern_ai = PatternWeightedAI(self.df)
    
    def _load_data(self):
        """Lädt Daten."""
        try:
            self.df = pd.read_csv(self.data_path, sep=';')
            if 'datum' in self.df.columns:
                self.df['datum'] = pd.to_datetime(self.df['datum'], format='%Y-%m-%d', errors='coerce')
                self.df = self.df.sort_values('datum')
            print(f"✅ {len(self.df)} Ziehungen geladen")
        except Exception as e:
            print(f"❌ Fehler beim Laden: {e}")
            self.df = pd.DataFrame()
    
    def generate_pattern_optimized_tips(self, num_tips=10):
        """Generiert Tipps mit expliziter Muster-Gewichtung."""
        
        if not self.pattern_ai:
            print("❌ Pattern AI nicht verfügbar")
            return []
        
        print("\n🎨 PATTERN-OPTIMIERTE TIPP-GENERIERUNG")
        print("=" * 60)
        
        # Muster-Empfehlungen abrufen
        recommendations = self.pattern_ai.get_pattern_recommendations()
        
        print("🎯 MUSTER-EMPFEHLUNGEN:")
        print(f"   Bestes Muster: {recommendations.get('best_pattern', 'N/A')} ({recommendations.get('best_success_rate', 0)*100:.1f}%)")
        print(f"   Top 5 Muster: {', '.join(recommendations.get('top_patterns', [])[:5])}")
        print(f"   Pattern-Diversität: {recommendations.get('pattern_diversity', 0)} erfolgreiche Muster")
        
        tips = []
        
        print(f"\n🎲 GENERIERE {num_tips} PATTERN-OPTIMIERTE TIPPS:")
        print("=" * 80)
        print("Nr  6 Pattern-Numbers       Pattern   Weight  Confidence  Success-Rate")
        print("-" * 80)
        
        # Verschiedene Strategien für verschiedene Tipps
        strategies = [
            ('best', "Bestes Muster"),
            ('top5', "Top 5 Rotation"),
            ('balanced', "Ausgewogene Muster"),
            ('diverse', "Diversifizierte Muster")
        ]
        
        for i in range(1, num_tips + 1):
            strategy = strategies[(i-1) % len(strategies)]
            tip = self._generate_pattern_tip(i, strategy[0], recommendations)
            tips.append(tip)
            
            # Output
            zahlen_str = '-'.join([f"{n:2}" for n in tip['numbers']])
            success_rate = self.pattern_ai.pattern_success_rates.get(tip['pattern'], 0)
            
            print(f"{i:2}  {zahlen_str}  {tip['pattern']:<8}  {tip['pattern_weight']:.3f}   {tip['confidence']:.3f}     {success_rate:.3f}")
        
        # Zusammenfassung
        self._print_pattern_summary(tips)
        
        return tips
    
    def _generate_pattern_tip(self, tip_number, strategy, recommendations):
        """Generiert einzelnen pattern-optimierten Tipp."""
        
        # Seed für Konsistenz
        random.seed(42 + tip_number)
        
        if strategy == 'best':
            # Nutze bestes Muster
            target_pattern = recommendations.get('best_pattern', 'NNMMHH')
        elif strategy == 'top5':
            # Rotiere durch Top 5
            top_patterns = recommendations.get('top_patterns', ['NNMMHH'])
            target_pattern = top_patterns[(tip_number - 1) % len(top_patterns)]
        elif strategy == 'balanced':
            # Ausgewogene beliebte Muster
            balanced_patterns = ['NNMMHH', 'NMMHHH', 'NMMMHH', 'NNMHHH']
            target_pattern = balanced_patterns[(tip_number - 1) % len(balanced_patterns)]
        else:  # diverse
            # Diversifizierte Muster für Abdeckung
            diverse_patterns = ['NNMMHH', 'MMHHHH', 'NNNNMM', 'NMHHHH', 'NNNMMH']
            target_pattern = diverse_patterns[(tip_number - 1) % len(diverse_patterns)]
        
        # Generiere Kombination für Ziel-Muster
        numbers = self.pattern_ai.optimize_combination_for_pattern(target_pattern)
        
        # Validiere und korrigiere falls nötig
        actual_pattern = self.pattern_ai._get_pattern(numbers)
        
        # Pattern Weight berechnen
        pattern_weight = self.pattern_ai.calculate_pattern_weight(numbers)
        
        # Confidence basierend auf Pattern Success Rate
        success_rate = self.pattern_ai.pattern_success_rates.get(actual_pattern, 0.01)
        confidence = pattern_weight * 0.6 + success_rate * 0.4
        
        # Superzahl
        superzahl = self._get_pattern_superzahl(tip_number)
        
        return {
            'tip_number': tip_number,
            'numbers': numbers,
            'pattern': actual_pattern,
            'target_pattern': target_pattern,
            'pattern_weight': pattern_weight,
            'confidence': confidence,
            'success_rate': success_rate,
            'superzahl': superzahl,
            'strategy': strategy
        }
    
    def _get_pattern_superzahl(self, tip_number):
        """Pattern-optimierte Superzahl."""
        # Basis häufigste Superzahlen
        frequent_sz = [7, 6, 3, 2, 0, 1, 4, 5, 8, 9]
        
        # Tip-spezifische Auswahl
        return frequent_sz[tip_number % len(frequent_sz)]
    
    def _print_pattern_summary(self, tips):
        """Druckt Pattern-Zusammenfassung."""
        print(f"\n🏆 PATTERN-OPTIMIERUNG ZUSAMMENFASSUNG:")
        print("=" * 50)
        
        # Pattern-Verteilung
        pattern_dist = Counter([tip['pattern'] for tip in tips])
        print("📊 PATTERN-VERTEILUNG:")
        for pattern, count in pattern_dist.most_common():
            avg_success = np.mean([self.pattern_ai.pattern_success_rates.get(pattern, 0)] * count)
            print(f"   {pattern}: {count}x (Ø Success: {avg_success:.3f})")
        
        # Durchschnittliche Metriken
        avg_weight = np.mean([tip['pattern_weight'] for tip in tips])
        avg_confidence = np.mean([tip['confidence'] for tip in tips])
        avg_success = np.mean([tip['success_rate'] for tip in tips])
        
        print(f"\n📈 DURCHSCHNITTLICHE METRIKEN:")
        print(f"   Pattern-Weight: {avg_weight:.3f}")
        print(f"   Confidence: {avg_confidence:.3f}")
        print(f"   Success-Rate: {avg_success:.3f}")
        
        # Beste Tipps
        best_tip = max(tips, key=lambda x: x['confidence'])
        print(f"\n⭐ BESTER PATTERN-TIPP:")
        zahlen_str = '-'.join([f"{n:2}" for n in best_tip['numbers']])
        print(f"   Tipp {best_tip['tip_number']}: {zahlen_str}")
        print(f"   Pattern: {best_tip['pattern']} (Weight: {best_tip['pattern_weight']:.3f})")
        print(f"   Success-Rate: {best_tip['success_rate']:.3f}")

def demonstrate_pattern_weighting():
    """Demonstriert Pattern-Gewichtung mit Beispiel-Daten."""
    
    print("🎨 PATTERN-GEWICHTUNG DEMONSTRATION")
    print("=" * 50)
    
    # Beispiel-Daten erstellen
    sample_data = []
    patterns_to_simulate = ['NNMMHH', 'NMMHHH', 'NMMMHH', 'NNMHHH', 'MMHHHH']
    
    for i in range(100):
        # Simuliere Ziehungen mit verschiedenen Mustern
        pattern = random.choice(patterns_to_simulate)
        numbers = []
        
        for char in pattern:
            if char == 'N':
                numbers.append(random.randint(1, 16))
            elif char == 'M':
                numbers.append(random.randint(17, 32))
            else:  # 'H'
                numbers.append(random.randint(33, 49))
        
        # Sicherstellen dass alle Zahlen einzigartig sind
        numbers = sorted(list(set(numbers)))
        while len(numbers) < 6:
            missing_range = random.choice(['N', 'M', 'H'])
            if missing_range == 'N':
                new_num = random.randint(1, 16)
            elif missing_range == 'M':
                new_num = random.randint(17, 32)
            else:
                new_num = random.randint(33, 49)
            
            if new_num not in numbers:
                numbers.append(new_num)
                numbers.sort()
        
        numbers = numbers[:6]
        
        sample_data.append({
            'Z1': numbers[0], 'Z2': numbers[1], 'Z3': numbers[2],
            'Z4': numbers[3], 'Z5': numbers[4], 'Z6': numbers[5],
            'SZ': random.randint(0, 9)
        })
    
    # DataFrame erstellen
    df_sample = pd.DataFrame(sample_data)
    
    # Enhanced AI Generator mit Pattern-Gewichtung
    print("\n🚀 STARTE PATTERN-GEWICHTETEN GENERATOR...")
    
    # Simuliere Generator
    generator = EnhancedAIGenerator.__new__(EnhancedAIGenerator)
    generator.df = df_sample
    generator.pattern_ai = PatternWeightedAI(df_sample)
    
    # Generiere pattern-optimierte Tipps
    pattern_tips = generator.generate_pattern_optimized_tips(8)
    
    print(f"\n💡 PATTERN-GEWICHTUNG ERKLÄRT:")
    print("=" * 40)
    print("🎯 Jede Kombination wird bewertet basierend auf:")
    print("   1. Historischer Erfolgsquote des Musters")
    print("   2. Bonus für Top-5 erfolgreichste Muster")
    print("   3. Penalty für nie aufgetretene Muster")
    print("   4. Kombinierte Pattern-Weight für finalen Score")
    
    return pattern_tips

def main():
    """Hauptfunktion für Pattern-gewichteten Generator."""
    data_path = "/Users/sebastianfrohlich/Library/Mobile Documents/com~apple~CloudDocs/Jupyter Notebooks/AlleLottozahlen.csv"
    
    try:
        # Versuche mit echten Daten
        generator = EnhancedAIGenerator(data_path)
        
        if generator.pattern_ai and len(generator.df) > 0:
            pattern_tips = generator.generate_pattern_optimized_tips(10)
        else:
            print("🔄 Echte Daten nicht verfügbar - verwende Demo...")
            pattern_tips = demonstrate_pattern_weighting()
        
    except Exception as e:
        print(f"⚠️ Fallback zu Demo-Modus: {e}")
        pattern_tips = demonstrate_pattern_weighting()

if __name__ == "__main__":
    main()
