"""
Advanced reward optimization for mining operations
"""
from typing import List, Dict, Any
import numpy as np
from collections import defaultdict

class TransactionFeeAnalyzer:
    def __init__(self):
        self.fee_history = defaultdict(list)
        self.min_profitable_fee = 50  # sat/byte
        
    def analyze(self, transactions: List[Dict]) -> Dict[str, Any]:
        """Analyze transaction fees for optimization"""
        fee_stats = {
            'total_fees': 0,
            'fee_rates': [],
            'optimal_transactions': []
        }
        
        for tx in transactions:
            fee_rate = tx['fee'] / tx['size']
            fee_stats['fee_rates'].append(fee_rate)
            fee_stats['total_fees'] += tx['fee']
            
            # Track history for this transaction
            tx_id = tx['txid']
            self.fee_history[tx_id].append(fee_rate)
            
            # Check if profitable
            if fee_rate >= self.min_profitable_fee:
                fee_stats['optimal_transactions'].append(tx)
                
        return fee_stats
        
class MempoolMonitor:
    def __init__(self):
        self.mempool_state = defaultdict(dict)
        self.fee_thresholds = [5, 10, 20, 50, 100]  # sat/byte
        
    def update_mempool(self, transactions: List[Dict]):
        """Update mempool state with new transactions"""
        current_time = time.time()
        
        for tx in transactions:
            self.mempool_state[tx['txid']] = {
                'fee_rate': tx['fee'] / tx['size'],
                'size': tx['size'],
                'time_seen': current_time
            }
            
    def get_optimal_fees(self) -> Dict[str, float]:
        """Calculate optimal fee rates based on mempool state"""
        fee_stats = defaultdict(list)
        
        for tx_data in self.mempool_state.values():
            fee_stats[self._get_fee_bucket(tx_data['fee_rate'])].append(
                tx_data['fee_rate']
            )
            
        return {
            bucket: np.median(rates) 
            for bucket, rates in fee_stats.items()
        }
        
    def _get_fee_bucket(self, fee_rate: float) -> str:
        """Get fee bucket for rate"""
        for threshold in self.fee_thresholds:
            if fee_rate <= threshold:
                return f"under_{threshold}"
        return "over_100"

class RewardOptimizer:
    def __init__(self):
        self.fee_analyzer = TransactionFeeAnalyzer()
        self.mempool_monitor = MempoolMonitor()
        self.block_size_limit = 4_000_000  # Maximum block size in bytes
        
    def optimize_block_template(self, transactions: List[Dict]) -> Dict[str, Any]:
        """Optimize block template for maximum reward"""
        # Analyze fees
        fee_stats = self.fee_analyzer.analyze(transactions)
        
        # Update mempool state
        self.mempool_monitor.update_mempool(transactions)
        
        # Get optimal fee rates
        optimal_fees = self.mempool_monitor.get_optimal_fees()
        
        # Select optimal transactions
        selected_txs = self.select_optimal_transactions(
            transactions,
            optimal_fees
        )
        
        return self.construct_block_template(selected_txs)
        
    def select_optimal_transactions(self, 
                                 transactions: List[Dict],
                                 fee_rates: Dict[str, float]) -> List[Dict]:
        """Select optimal transactions for maximum reward"""
        # Sort by fee/size ratio
        sorted_txs = sorted(
            transactions,
            key=lambda x: x['fee'] / x['size'],
            reverse=True
        )
        
        selected = []
        total_size = 0
        
        for tx in sorted_txs:
            # Check if transaction fits
            if total_size + tx['size'] <= self.block_size_limit:
                # Check if fee rate is profitable
                if tx['fee'] / tx['size'] >= self.fee_analyzer.min_profitable_fee:
                    selected.append(tx)
                    total_size += tx['size']
                    
        return selected
        
    def construct_block_template(self, transactions: List[Dict]) -> Dict[str, Any]:
        """Construct optimized block template"""
        return {
            'version': 2,
            'transactions': transactions,
            'total_fees': sum(tx['fee'] for tx in transactions),
            'total_size': sum(tx['size'] for tx in transactions),
            'timestamp': int(time.time())
        }
