"""
Simple personal mining reward system using whole numbers.
Rewards based on your hash rate and how fast you find solutions.
"""
from decimal import Decimal
import json
import time
from typing import Dict, Any, List, Optional, TYPE_CHECKING

# Use TYPE_CHECKING to avoid circular imports
if TYPE_CHECKING:
    from .wallet import BTCWallet

class RewardSystem:
    def __init__(self):
        # Balanced reward scaling for all hash rates (all integers)
        self.reward_per_khash = 1      # Reward per 1000 hashes
        self.min_reward = 100          # Minimum 100 coins per solution
        self.speed_bonus = 100         # Speed bonus
        self.solution_bonus = 100      # Fixed bonus per solution
        self.max_base_reward = 1000    # Cap on base hash reward
        
        # Performance tracking
        self.last_hash_rates: List[int] = []  # Track last N hash rates
        self.max_tracked_rates = 10  # Number of hash rates to track
        self.min_hash_rate = 1000  # Minimum hash rate (1 KH/s)
        
    def calculate_reward(self, hash_rate: int, time_taken: float) -> int:
        """
        Balanced reward calculation using whole numbers:
        1. Rewards per 1000 hashes (kilohash)
        2. Fixed bonus for solutions
        3. Speed bonus
        4. Capped base reward to prevent overflow
        Perfect for both casual and serious mining!
        """
        # Convert hash rate to kilohashes and calculate base reward
        khash_rate = hash_rate // 1000  # Integer division
        base_reward = khash_rate * self.reward_per_khash
        
        # Cap the base reward
        base_reward = min(base_reward, self.max_base_reward)
        
        # Fixed bonus for finding a solution
        solution_bonus = self.solution_bonus
        
        # Speed bonus (higher for faster solutions)
        speed_bonus = self.speed_bonus // max(int(time_taken), 1)
        
        # Calculate total reward (minimum 100)
        total_reward = base_reward + solution_bonus + speed_bonus
        final_reward = max(total_reward, self.min_reward)
        
        # Record reward to be processed by server
        self._record_pending_reward({
            'amount': final_reward,
            'timestamp': time.time(),
            'base_reward': base_reward,
            'solution_bonus': solution_bonus,
            'speed_bonus': speed_bonus,
            'stats': {
                'khash_rate': khash_rate,
                'time_taken': time_taken
            }
        })
        
        return final_reward
        
    def _record_pending_reward(self, reward_data: Dict[str, Any]):
        """Record reward for server processing"""
        try:
            import json
            # Format the reward data for database
            db_record = {
                'reward_amount': reward_data['amount'],  # Already an integer
                'timestamp': reward_data['timestamp'],
                'components': {
                    'base': reward_data['base_reward'],
                    'solution': reward_data['solution_bonus'],
                    'speed': reward_data['speed_bonus']
                },
                'performance': {
                    'khash_rate': reward_data['stats']['khash_rate'],
                    'time_taken': reward_data['stats']['time_taken']
                },
                'status': 'pending'
            }
            
            # Server will pick this up and process it
            with open('pending_rewards.json', 'a') as f:
                f.write(json.dumps(db_record) + '\n')
        except Exception as e:
            print(f"Error recording reward: {e}")
        
    
    def _update_performance_history(self, hash_rate: int):
        """Update performance tracking with latest hash rate"""
        self.last_hash_rates.append(hash_rate)
        if len(self.last_hash_rates) > self.max_tracked_rates:
            self.last_hash_rates.pop(0)
    
    def get_performance_stats(self) -> Dict[str, Any]:
        """Get performance statistics"""
        if not self.last_hash_rates:
            return {
                'recent_rates': [],
                'trend': 0,
                'average': 0
            }
            
        trend = 0
        if len(self.last_hash_rates) >= 2:
            trend = self.last_hash_rates[-1] - self.last_hash_rates[0]
            
        return {
            'recent_rates': self.last_hash_rates,
            'trend': trend,
            'average': sum(self.last_hash_rates) / len(self.last_hash_rates)
        }
    
    def _calculate_solution_uniqueness(self, solution_hash: str) -> Decimal:
        """Calculate how unique this solution is compared to recent solutions"""
        if not self.last_solutions:
            return Decimal('1.0')
            
        # Compare Hamming distance with recent solutions
        distances = []
        for prev_hash in self.last_solutions:
            distance = sum(a != b for a, b in zip(solution_hash, prev_hash))
            distances.append(distance)
            
        # Average distance normalized to [0.1, 1.0]
        avg_distance = sum(distances) / len(distances)
        uniqueness = Decimal(str(0.1 + (0.9 * avg_distance / 64)))  # 64 is max distance for 32-byte hash
        
        return uniqueness
        
    def _calculate_efficiency_rating(self, hash_rate: Decimal, power_usage: float) -> Decimal:
        """Calculate efficiency rating compared to network average"""
        if power_usage <= 0:
            return Decimal('0.1')
            
        hashes_per_watt = hash_rate / Decimal(str(power_usage))
        # Scale to [0.1, 2.0] range - can earn up to 2x for being very efficient
        return Decimal('0.1') + (hashes_per_watt / Decimal('1000000'))
        
    def _update_network_state(self, hash_rate: Decimal, solution_hash: str):
        """Update network state with new mining data"""
        # Update total network hash power with decay factor
        decay = Decimal('0.95')  # 5% decay to adjust for inactive miners
        self.total_network_hash_power = (self.total_network_hash_power * decay) + hash_rate
        
        # Update recent solutions
        self.last_solutions.append(solution_hash)
        if len(self.last_solutions) > self.max_tracked_solutions:
            self.last_solutions.pop(0)
            
        # Adjust network difficulty based on solution rate
        self._adjust_network_difficulty()

    def process_mining_reward(self, 
                            wallet: 'BTCWallet', 
                            block_hash: str,
                            mining_stats: Dict[str, Any]) -> Dict[str, Any]:
        """Process mining reward based on hash rate and speed"""
        
        # Calculate reward based on performance
        reward_amount = self.calculate_reward(
            hash_rate=mining_stats.get('hash_rate', 0),
            time_taken=mining_stats.get('time_taken', 1)
        )
        
        # Update wallet balance
        wallet.update_balance(reward_amount)
        
        # Record the mining reward with performance metrics
        reward_record = {
            'block_hash': block_hash,
            'amount': float(reward_amount),
            'timestamp': int(time.time()),
            'wallet_address': wallet.get_address(),
            'performance_metrics': {
                'hash_rate': float(mining_stats.get('hash_rate', 0)),
                'difficulty': mining_stats.get('difficulty', 0),
                'power_usage': mining_stats.get('power_usage', 0),
                'time_taken': mining_stats.get('time_taken', 0),
            }
        }
        
        # Record in wallet's mining history
        wallet.record_mining_reward(reward_record)
        
        return reward_record
        
    def _update_performance_history(self, hash_rate: Decimal):
        """Update hash rate history for trend analysis"""
        self.last_hash_rates.append(float(hash_rate))
        if len(self.last_hash_rates) > self.max_tracked_rates:
            self.last_hash_rates.pop(0)
            
    def get_performance_stats(self) -> Dict[str, Any]:
        """Get mining performance statistics"""
        if not self.last_hash_rates:
            return {'average_hash_rate': 0, 'trend': 0}
            
        avg_hash_rate = sum(self.last_hash_rates) / len(self.last_hash_rates)
        trend = self.last_hash_rates[-1] - self.last_hash_rates[0] if len(self.last_hash_rates) > 1 else 0
        
        return {
            'average_hash_rate': avg_hash_rate,
            'trend': trend,
            'recent_rates': self.last_hash_rates[-5:]  # Last 5 hash rates
        }
