from src.mining.processor import MiningProcessor
from src.utils.logger import Logger
from src.core.simplified_block import SimplifiedBlock
from src.core.mining_validator import MiningValidator
from src.core.reward_system import RewardSystem
from src.core.wallet import BTCWallet
import time
import threading
from typing import Optional, Dict, Any

class EnhancedMiner:
    def __init__(self, wallet: BTCWallet):
        self.processor = MiningProcessor()
        self.logger = Logger()
        self.wallet = wallet
        self.validator = MiningValidator()
        self.reward_system = RewardSystem()
        self.running = False
        self.current_block: Optional[SimplifiedBlock] = None
        self.last_block_hash = "0" * 64  # Genesis block hash
        self.mining_thread: Optional[threading.Thread] = None

    def start(self):
        """Start mining operations"""
        if self.mining_thread and self.mining_thread.is_alive():
            self.logger.warning("Mining already running")
            return
            
        self.running = True
        self.mining_thread = threading.Thread(target=self._mining_loop)
        self.mining_thread.daemon = True
        self.mining_thread.start()
        self.logger.info("Mining operations started")
        
    def _mining_loop(self):
        """Main mining loop"""
        try:
            self.logger.info("Initializing enhanced miner...")
            self.processor.initialize()
            
            while self.running:
                try:
                    # Create new block template
                    self.current_block = self.get_block_template()
                    
                    # Prepare batch for processing
                    batch_data = self.processor.prepare_mining_batch(
                        self.current_block.to_dict()
                    )
                    
                    # Process mining batch
                    result = self.processor.process_mining_batch(batch_data)
                    
                    if result and self.validator.verify_hash(result['hash']):
                        self.handle_mining_result(result)
                    else:
                        # Update timestamp and try again
                        self.current_block.timestamp = int(time.time())
                        time.sleep(0.1)  # Small delay to prevent CPU overload
                        
                except Exception as e:
                    self.logger.error(f"Error in mining loop: {str(e)}")
                    time.sleep(5)
                    
        except Exception as e:
            self.logger.error(f"Critical error in miner: {str(e)}")
            self.stop()
            raise

    def stop(self):
        """Stop mining operations"""
        self.running = False
        self.processor.cleanup()
        self.logger.info("Mining operations stopped")

    def get_block_template(self) -> SimplifiedBlock:
        """Create new block template for mining"""
        block = SimplifiedBlock()
        block.prev_block_hash = self.last_block_hash
        block.miner_address = self.wallet.get_address()
        return block

    def handle_mining_result(self, result: Dict[str, Any]):
        """Handle successful mining result"""
        if result and self.validator.verify_hash(result['hash']):
            self.logger.info(f"Successfully mined block with hash: {result['hash']}")
            
            # Calculate mining performance metrics
            mining_stats = self._calculate_mining_stats(result)
            
            # Process mining reward with performance metrics
            reward = self.reward_system.process_mining_reward(
                self.wallet,
                result['hash'],
                mining_stats
            )
            
            # Update last block hash for next mining round
            self.last_block_hash = result['hash']
            
            # Log detailed performance and reward info
            self.logger.info(
                f"Processed mining reward: {reward['amount']} coins\n"
                f"Hash Rate: {mining_stats['hash_rate']/1000:.2f} KH/s\n"
                f"Difficulty: {mining_stats['difficulty']}\n"
                f"Power Efficiency: {mining_stats['hash_rate']/mining_stats['power_usage']:.2f} H/W"
            )
            
    def _calculate_mining_stats(self, result: Dict[str, Any]) -> Dict[str, Any]:
        """Calculate mining performance statistics"""
        # Get number of leading zeros in hash as difficulty measure
        difficulty = len(result['hash']) - len(result['hash'].lstrip('0'))
        
        # Calculate time taken
        time_taken = time.time() - self.current_block.timestamp
        
        # Get hash rate from processor
        hash_rate = self.processor.get_hash_rate()
        
        # Get power usage (example implementation)
        power_usage = self.processor.get_power_usage() if hasattr(self.processor, 'get_power_usage') else 100
        
        return {
            'hash_rate': hash_rate,
            'difficulty': difficulty,
            'power_usage': power_usage,
            'time_taken': time_taken
        }
