"""
Mining-optimized memory manager
"""
from typing import Dict, Any, Optional, Tuple
import mmap
import threading
import time
import logging

class MiningMemoryManager:
    """Ultra-efficient memory manager for mining operations"""
    
    def __init__(self):
        self.block_size = 256  # Size of SHA-256 block
        self.max_concurrent_blocks = 1024  # Max blocks per GPU
        self.block_lifetime_ms = 100  # 100ms block lifetime
        
        # Memory tracking
        self.active_blocks = {}  # {block_id: (mmap_block, creation_time)}
        self.allocated_bytes = 0
        self.lock = threading.Lock()
        
        # Start cleanup thread
        self.running = True
        self.cleanup_thread = threading.Thread(target=self._cleanup_loop, daemon=True)
        self.cleanup_thread.start()
        
    def allocate_block(self) -> Tuple[int, memoryview]:
        """Allocate a minimal block for mining"""
        with self.lock:
            # Force cleanup if at capacity
            if len(self.active_blocks) >= self.max_concurrent_blocks:
                self._force_cleanup()
                
            # Create anonymous memory mapping
            block_id = len(self.active_blocks)
            block = mmap.mmap(-1, self.block_size)
            view = memoryview(block)
            
            self.active_blocks[block_id] = (block, time.time())
            self.allocated_bytes += self.block_size
            
            return block_id, view
            
    def free_block(self, block_id: int):
        """Immediately free a block"""
        with self.lock:
            if block_id in self.active_blocks:
                block, _ = self.active_blocks.pop(block_id)
                block.close()
                self.allocated_bytes -= self.block_size
                
    def _force_cleanup(self):
        """Immediate cleanup of old blocks"""
        current_time = time.time()
        with self.lock:
            for block_id, (block, creation_time) in list(self.active_blocks.items()):
                if (current_time - creation_time) * 1000 > self.block_lifetime_ms:
                    block.close()
                    del self.active_blocks[block_id]
                    self.allocated_bytes -= self.block_size
                    
    def _cleanup_loop(self):
        """Background cleanup thread"""
        while self.running:
            self._force_cleanup()
            # Run cleanup at half the block lifetime
            time.sleep(self.block_lifetime_ms / 2000)
            
    def get_stats(self) -> Dict[str, Any]:
        """Get current memory usage statistics"""
        with self.lock:
            return {
                "active_blocks": len(self.active_blocks),
                "allocated_bytes": self.allocated_bytes,
                "utilization": len(self.active_blocks) / self.max_concurrent_blocks,
                "block_size": self.block_size,
                "max_blocks": self.max_concurrent_blocks
            }
            
    def __del__(self):
        """Cleanup on deletion"""
        self.running = False
        if hasattr(self, 'cleanup_thread'):
            self.cleanup_thread.join(timeout=1.0)
        with self.lock:
            for block, _ in self.active_blocks.values():
                block.close()
