from src.hardware.hardware_manager import HardwareManager
from src.utils.logger import Logger
from cpu.enhanced_cpu import CPUGrid, CPUGroupType, CPUInstruction, InstructionType
import numpy as np

class MiningProcessor:
    def __init__(self):
        self.logger = Logger()
        self.cpu_grid = CPUGrid()
        self.hardware = HardwareManager()
        self.computation_group = CPUGroupType.COMPUTATION
        self.io_group = CPUGroupType.IO_STORAGE

    def initialize(self):
        """Initialize mining processor with enhanced CPU architecture"""
        self.logger.info("Initializing mining processor with enhanced CPU grid...")
        
        # Initialize hardware components
        self.hardware.initialize()
        
        # Verify computation CPUs availability
        self.computation_cpus = []
        for cpu_id in range(500, 1000):  # Computation group range
            cpu = self.cpu_grid.get_cpu(cpu_id)
            if cpu:
                self.computation_cpus.append(cpu)
        
        self.logger.info(f"Initialized {len(self.computation_cpus)} computation CPUs")

    def prepare_mining_batch(self, block_template):
        """Prepare mining data using I/O group CPUs"""
        io_cpu = self.cpu_grid.get_available_cpu(CPUGroupType.IO_STORAGE)
        if not io_cpu:
            raise RuntimeError("No available I/O CPUs")

        # Create data processing instruction
        instruction = CPUInstruction(
            type=InstructionType.MEMORY,
            opcode=0x01,  # READ
            operands=[0, len(block_template)],
            data=block_template.encode()
        )
        
        # Process the data using I/O CPU
        io_cpu.schedule_instruction(instruction)
        
        # Convert to numpy array for tensor operations
        data = np.frombuffer(block_template.encode(), dtype=np.uint8)
        return data.reshape(-1, 256)  # 256-byte chunks

    def process_mining_batch(self, batch_data):
        """Process mining data using computation group CPUs"""
        try:
            # Distribute work across computation CPUs
            chunks_per_cpu = len(batch_data) // len(self.computation_cpus)
            
            for i, cpu in enumerate(self.computation_cpus):
                start_idx = i * chunks_per_cpu
                end_idx = start_idx + chunks_per_cpu if i < len(self.computation_cpus) - 1 else len(batch_data)
                
                # Create computation instruction
                instruction = CPUInstruction(
                    type=InstructionType.ARITHMETIC,
                    opcode=0x01,  # Mining computation opcode
                    operands=[start_idx, end_idx],
                    data=batch_data[start_idx:end_idx].tobytes()
                )
                
                # Schedule the instruction
                cpu.schedule_instruction(instruction)

            # Monitor hardware status
            status = self.monitor_status()
            self.logger.info(f"Hardware status: {status}")
            
            return True

        except Exception as e:
            self.logger.error(f"Error in mining batch processing: {str(e)}")
            return None

    def monitor_status(self):
        """Monitor CPU grid and hardware status"""
        # Get CPU utilization for computation group
        cpu_status = {
            'computation_cpus': sum(1 for cpu in self.computation_cpus if cpu.busy_cores > 0),
            'total_computation_cpus': len(self.computation_cpus),
            'busy_cores': sum(cpu.busy_cores for cpu in self.computation_cpus),
            'total_cores': sum(cpu.core_count for cpu in self.computation_cpus),
            'busy_threads': sum(cpu.busy_threads for cpu in self.computation_cpus),
            'total_threads': sum(cpu.thread_count * cpu.core_count for cpu in self.computation_cpus)
        }

        # Get hardware status
        hardware_status = self.hardware.monitor_hardware_status()

        return {
            'cpu_status': cpu_status,
            'hardware_status': hardware_status
        }

    def cleanup(self):
        """Cleanup processor resources"""
        self.logger.info("Shutting down mining processor...")
        self.cpu_grid.shutdown()
        self.hardware.cleanup_resources()
