
import sys
import os
import time
import hashlib
import random
import sqlite3
from decimal import Decimal
from typing import Dict, Any, Tuple
from hashlib import sha256  # Explicit import for Bitcoin's double SHA256
from local_storage_manager import LocalStorageManager
from bitcoin_network_robust import BitcoinNetworkRobust
from wallet_verifier import WalletVerifier
from network_integration import NetworkIntegration
from btc_address_utils import BitcoinAddressUtils
from check_real_balance import check_network_balance
from storage_cleanup import StorageCleanup
from cpu.enhanced_cpu import EnhancedCPU, VirtualCPU, CPUGroupType

# Ensure data directory exists
os.makedirs("data", exist_ok=True)

class MiningConfig:
    """Configuration for CPU mining parameters"""
    def __init__(self):
        self.test_duration = 120  # seconds - 2 minutes for testing
        self.total_cpus = 1_000_000  # 1 million quantum CPUs
        self.batch_size = 10_000  # Process 10k CPUs at a time for better responsiveness
        self.hashes_per_batch = 100_000  # 100k hashes per CPU batch
        self.cores_per_cpu = 100_000  # 100k cores per CPU - quantum setup
        self.threads_per_core = 1_000  # 1k threads per core - quantum setup
        self.difficulty_bits = 0x1e0fffff  # Testing difficulty
        self.block_reward = None  # Will be fetched from network
        self.log_interval = 1  # Log every second

class MiningStats:
    """Track CPU mining statistics"""
    def __init__(self):
        self.real_hashes_done = 0  # Hashes in current interval
        self.total_real_hashes = 0  # Total hashes since start
        self.last_update_time = time.time()
        self.quantum_start_time = time.time()
        self.avg_hash_rate = 0
        self.blocks_found = 0
        self.last_block_time = None
        self.total_rewards = Decimal('0')

def init_cpu_config(storage, config):
    """Initialize CPU configuration table"""
    storage.cursor.execute("""
        CREATE TABLE IF NOT EXISTS cpu_config (
            cpu_id INTEGER PRIMARY KEY,
            core_count INTEGER,
            thread_count INTEGER
        )
    """)
    
    # Add CPU configurations
    storage.cursor.execute("DELETE FROM cpu_config")  # Clear existing
    for cpu_id in range(config.total_cpus):
        storage.cursor.execute(
            "INSERT INTO cpu_config (cpu_id, core_count, thread_count) VALUES (?, ?, ?)",
            (cpu_id, config.cores_per_cpu, config.threads_per_core)
        )
    storage.conn.commit()

# Initialize storage with retries
max_retries = 3
for retry in range(max_retries):
    try:
        if os.path.exists("data/cpu_storage.db"):
            os.remove("data/cpu_storage.db")  # Start fresh to avoid locking issues
        storage = LocalStorageManager(db_path="data/cpu_storage.db")
        storage._setup_mining_tables()
        break
    except Exception as e:
        if retry == max_retries - 1:
            raise
        time.sleep(1)  # Wait before retrying
from check_real_balance import check_network_balance

class MiningConfig:
    """Configuration for CPU mining parameters"""
    def __init__(self):
        self.test_duration = 60  # seconds - increased for better testing
        self.total_cpus = 1_000_000  # 1 million quantum CPUs
        self.batch_size = 10_000  # Process 10k CPUs at a time for better responsiveness
        self.hashes_per_batch = 100_000  # Hashes per CPU batch
        self.cores_per_cpu = 100_000  # 100k cores per CPU - more realistic
        self.threads_per_core = 1_000  # 1k threads per core - more realistic
        self.difficulty_bits = 0x1e0fffff  # Easier difficulty for testing
        self.block_reward = None  # Will be fetched from network
        self.log_interval = 1  # Log every second

class MiningStats:
    """Track CPU mining statistics"""
    def __init__(self):
        self.real_hashes_done = 0  # Hashes in current interval
        self.total_real_hashes = 0  # Total hashes since start
        self.last_update_time = time.time()
        self.quantum_start_time = time.time()
        self.avg_hash_rate = 0
        self.blocks_found = 0
        self.last_block_time = None
        self.total_rewards = Decimal('0')
        self.total_fees = Decimal('0')
import hashlib
import random
from typing import Tuple, Dict, Any

# Add project root to path to allow imports
project_root = os.path.dirname(os.path.abspath(__file__))
if project_root not in sys.path:
    sys.path.insert(0, project_root)

# Third-party imports
from decimal import Decimal

# CPU and Storage components
from cpu.enhanced_cpu import EnhancedCPU, VirtualCPU, CPUGroupType
from local_storage_manager import LocalStorageManager
from storage_cleanup import StorageCleanup

# Bitcoin network components
from bitcoin_network_robust import BitcoinNetworkRobust
from wallet_verifier import WalletVerifier
from network_integration import NetworkIntegration
from btc_address_utils import BitcoinAddressUtils
# Mining configuration class
class MiningConfig:
    """Configuration for CPU mining parameters"""
    def __init__(self):
        self.test_duration = 60  # seconds - increased for better testing
        self.total_cpus = 1_000_000  # 1 million quantum CPUs
        self.batch_size = 10_000  # Process 10k CPUs at a time
        self.hashes_per_batch = 100_000  # Hashes per CPU batch
        self.cores_per_cpu = 100_000  # 100k cores per CPU
        self.threads_per_core = 1_000  # 1k threads per core
        self.difficulty_bits = 0x1e0fffff  # Test difficulty
        self.block_reward = None  # Will be fetched from network
        self.log_interval = 1  # Log every second

# Mining statistics class
class MiningStats:
    def __init__(self):
        self.real_hashes_done = 0
        self.total_real_hashes = 0
        self.last_update_time = time.time()
        self.quantum_start_time = None
        self.avg_hash_rate = 0
        self.blocks_found = 0
        self.total_rewards = Decimal('0')
        self.last_block_time = None
        self.blocks_history = []  # Store block finding history
        
    def log_block_found(self, block_height, reward, fees):
        """Log when a new block is found"""
        self.blocks_found += 1
        current_time = time.time()
        self.last_block_time = current_time
        total_reward = reward + fees
        self.total_rewards += Decimal(str(total_reward))
        
        block_info = {
            'height': block_height,
            'time': current_time,
            'reward': reward,
            'fees': fees,
            'total_reward': total_reward
        }
        self.blocks_history.append(block_info)
        
        # Log to file
        with open('mining_rewards.log', 'a') as f:
            f.write(f"\nBlock found at {time.strftime('%Y-%m-%d %H:%M:%S')}:\n")
            f.write(f"Height: {block_height}\n")
            f.write(f"Reward: {reward} BTC\n")
            f.write(f"Fees: {fees} BTC\n")
            f.write(f"Total Reward: {total_reward} BTC\n")
            f.write(f"Total Rewards So Far: {self.total_rewards} BTC\n")
            f.write("-" * 50 + "\n")

def get_mock_block_template() -> Dict[str, Any]:
    """Generate a mock block template for testing without network"""
    return {
        'version': 536870912,
        'previousblockhash': '000000000000000000046dda034a4a758924fc6b09551fa4ba0c812b902086ed',
        'height': 800000,
        'coinbasevalue': 625000000,  # 6.25 BTC in satoshis
        'transactions': [],
        'target': '0x1e0fffff',  # Easy target for testing
        'mintime': int(time.time()),
        'mutable': ['time', 'transactions', 'prevblock'],
        'noncerange': '00000000ffffffff',
        'sigoplimit': 80000,
        'sizelimit': 4000000,
        'weightlimit': 4000000,
        'curtime': int(time.time()),
        'bits': '1e0fffff',
        'difficulty': 1
    }

def get_block_reward(template: Dict[str, Any], use_mock: bool = True) -> Dict[str, Any]:
    """Extract reward information from block template"""
    if use_mock:
        template = get_mock_block_template()
    
    base_reward = 6.25  # Current base reward
    fees = sum(tx.get('fee', 0) for tx in template.get('transactions', []))
    return {
        'height': template.get('height', 800000),
        'base_reward': base_reward,
        'fees': fees / 100000000,  # Convert satoshis to BTC
        'total': base_reward + (fees / 100000000),
        'timestamp': template.get('curtime', int(time.time())),
        'n_transactions': len(template.get('transactions', []))
    }

def get_target(bits_str: str) -> int:
    """Convert difficulty bits to target"""
    bits = int(bits_str, 16)
    shift = (bits >> 24) & 0xff
    value = bits & 0x00ffffff
    target = value << (8 * (shift - 3))
    return target

# Initialize storage and ensure tables exist
os.makedirs("data", exist_ok=True)
try:
    if os.path.exists("data/cpu_storage.db"):
        os.remove("data/cpu_storage.db")  # Start fresh to avoid locking issues
except:
    pass
storage = LocalStorageManager(db_path="data/cpu_storage.db")

def init_database():
    """Initialize fresh database"""
    try:
        if os.path.exists("data/cpu_storage.db"):
            os.remove("data/cpu_storage.db")
    except:
        pass
    return LocalStorageManager(db_path="data/cpu_storage.db")

storage = init_database()

def setup_mining_tables(storage):
    """Setup enhanced mining tables to track all details"""
    # Drop existing tables to ensure clean slate
    tables = ['mining_stats', 'cpu_config', 'mining_blocks', 'hashrate_history']
    for table in tables:
        storage.cursor.execute(f"DROP TABLE IF EXISTS {table}")
    
    # Create fresh tables
    storage.cursor.execute("""
        CREATE TABLE mining_stats (
            test_id INTEGER PRIMARY KEY,
            total_hashes BIGINT DEFAULT 0,
            start_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
            end_time TIMESTAMP,
            avg_hashrate FLOAT DEFAULT 0,
            blocks_found INTEGER DEFAULT 0,
            total_rewards FLOAT DEFAULT 0
        )
    """)
    
    storage.cursor.execute("""
        CREATE TABLE IF NOT EXISTS cpu_config (
            cpu_id INTEGER PRIMARY KEY,
            core_count INTEGER,
            thread_count INTEGER,
            initialized INTEGER DEFAULT 0,
            total_hashes BIGINT DEFAULT 0,
            blocks_found INTEGER DEFAULT 0,
            last_nonce BIGINT DEFAULT 0
        )
    """)
    
    storage.cursor.execute("""
        CREATE TABLE IF NOT EXISTS mining_blocks (
            block_id INTEGER PRIMARY KEY AUTOINCREMENT,
            test_id INTEGER,
            cpu_id INTEGER,
            block_height INTEGER,
            nonce INTEGER,
            hash TEXT,
            reward FLOAT,
            timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
            FOREIGN KEY(test_id) REFERENCES mining_stats(test_id),
            FOREIGN KEY(cpu_id) REFERENCES cpu_config(cpu_id)
        )
    """)
    
    storage.cursor.execute("""
        CREATE TABLE IF NOT EXISTS hashrate_history (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            test_id INTEGER,
            timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
            interval_hashes BIGINT,
            interval_seconds FLOAT,
            hashrate FLOAT,
            FOREIGN KEY(test_id) REFERENCES mining_stats(test_id)
        )
    """)
    storage.conn.commit()

setup_mining_tables(storage)  # Setup enhanced mining tables

def display_mining_results(test_id):
    """Display final mining results from database"""
    print("\n=== Final Mining Results from Database ===")
    
    # Get overall stats
    storage.cursor.execute("""
        SELECT total_hashes, 
               avg_hashrate,
               blocks_found,
               strftime('%s', end_time) - strftime('%s', start_time) as duration
        FROM mining_stats 
        WHERE test_id = ?
    """, (test_id,))
    stats = storage.cursor.fetchone()
    
    if stats:
        total_hashes, avg_hashrate, blocks_found, duration = stats
        print(f"\nTotal Runtime: {duration} seconds")
        print(f"Total Hashes: {total_hashes:,}")
        print(f"Average Hashrate: {avg_hashrate:,.2f} H/s")
        print(f"Blocks Found: {blocks_found}")
        
        # Get block details if any found
        if blocks_found > 0:
            print("\nBlocks Found:")
            storage.cursor.execute("""
                SELECT block_height, nonce, reward, strftime('%Y-%m-%d %H:%M:%S', timestamp)
                FROM mining_blocks 
                WHERE test_id = ?
                ORDER BY timestamp
            """, (test_id,))
            for height, nonce, reward, found_time in storage.cursor.fetchall():
                print(f"Height: {height}, Nonce: {nonce}, Reward: {reward} BTC, Found at: {found_time}")

def test_btc_mining():
    global storage
    cleanup_manager = None
    try:
        print("\n=== Bitcoin Mining Test Started ===\n")
        
        # Create or clear log file
        with open('mining_rewards.log', 'w') as f:
            f.write("=== Mining Rewards Log ===\n")
            f.write(f"Test started at: {time.strftime('%Y-%m-%d %H:%M:%S')}\n\n")
            
        # Skip network checks for testing
        print("Running in offline test mode...")
        
        # Verify storage connection and ensure tables exist
        if storage.cursor is None or storage.conn is None:
            storage = LocalStorageManager(db_path="data/cpu_storage.db")
            storage._setup_mining_tables()  # Ensure mining-specific tables exist
        # Initialize test parameters with optimized values for 1M CPUs
        start_time = time.time()
        test_duration = 30  # Run for 30 seconds in test mode
        TOTAL_CPUS = 1_000_000  # 1 million CPUs
        batch_size = 100_000  # Process 100k CPUs at a time for better memory management
        HASHES_PER_BATCH = 10_000  # Hashes per CPU for better responsiveness
        BTC_REWARD = 3.125  # Post-2024 halving reward
        # Use testnet difficulty for faster results
        DIFFICULTY_BITS = 0x1d00ffff  # Easier difficulty for testing
        DB_WRITE_INTERVAL = 5  # Only write to DB every 5 seconds
        blocks_found = 0
        total_reward = 0
        total_hashes = 0
        
        # Make sure data directory exists
        os.makedirs("data", exist_ok=True)
        
        # Initialize cleanup manager
        cleanup_manager = StorageCleanup("data/cpu_storage.db")
        
        # Clean existing data and ensure proper connection handling
        # Clean existing data with retry mechanism
        retries = 3
        while retries > 0:
            try:
                if storage.cursor is None or storage.conn is None:
                    storage._connect_db()
                
                # Clean existing tables
                storage.cursor.execute('DELETE FROM cpu_config')
                storage.cursor.execute('DELETE FROM core_state')
                storage.cursor.execute('DELETE FROM thread_state')
                storage.conn.commit()
                break
            except Exception as e:
                print(f"Database error (retries left: {retries}): {e}")
                retries -= 1
                time.sleep(1)  # Brief delay before retry
                try:
                    storage.conn.close()
                except:
                    pass
                storage = LocalStorageManager(db_path="data/cpu_storage.db")
        
        if retries == 0:
            raise Exception("Failed to initialize database after multiple retries")
        
        # Initialize system
        print(f"\nInitializing system for {TOTAL_CPUS:,} CPUs...")
        
        # Reset mining stats
        storage.cursor.execute("DELETE FROM mining_stats WHERE test_id = 1")
        storage.cursor.execute("""
        INSERT INTO mining_stats (test_id, total_hashes, start_time)
        VALUES (1, 0, CURRENT_TIMESTAMP)
        """)
        storage.conn.commit()
        
        # Initialize CPU system with config values
        config = MiningConfig()
        VirtualCPU.initialize_system(
            total_cpus=config.total_cpus,
            cores_per_cpu=config.cores_per_cpu,
            threads_per_core=config.threads_per_core,
            batch_size=config.batch_size
        )
        
        # Process CPUs in batches
        print("Preparing CPU references...")
        for batch_start in range(0, config.total_cpus, config.batch_size):
            batch_end = min(batch_start + config.batch_size, config.total_cpus)
            
            # Store CPU configurations
            storage.cursor.execute(
                """INSERT OR REPLACE INTO cpu_config 
                   (cpu_id, core_count, thread_count, initialized)
                   SELECT ?, ?, ?, 1
                   WHERE NOT EXISTS (
                       SELECT 1 FROM cpu_config WHERE cpu_id = ?
                   )""",
                (batch_start, config.cores_per_cpu, config.threads_per_core, batch_start)
            )
            
            if batch_start % 10_000_000 == 0:  # Report on major milestones
                print(f"Prepared {batch_start:,} CPU references...")
                try:
                    storage.cleanup()
                    storage.conn.commit()
                except Exception:
                    try:
                        time.sleep(0.1)  # Brief delay on error
                        storage.cleanup()
                        storage.conn.commit()
                    except Exception:
                        pass  # Silently continue on repeated error
        
        # Load and verify wallet
        print("\nLoading and verifying wallet...")
        wallet_path = os.path.join(project_root, "my_wallet.json")
        wallet = WalletVerifier(wallet_path=wallet_path)
        wallet_info = wallet.get_wallet_info()
        
        try:
            # Check real network balance
            print("\nChecking network balance...")
            from check_real_balance import check_network_balance
            check_network_balance(wallet_info['address'])
        except Exception as e:
            print(f"Warning: Failed to check network balance: {e}")
        
        # Initialize network connection with verified wallet
        print("\nConnecting to Bitcoin network...")
        network = BitcoinNetworkRobust(
            network='bitcoin',
            timeout=5,  # Reduced timeout for faster startup
            retries=2,
            wallet_address=wallet_info['address']
        )
        
        # Clear database locks
        storage.cleanup()
        storage.conn.commit()
        
        # Set start time for mining duration
        start_time = time.time()
        print(f"\nStarting mining test for {config.test_duration} seconds...")
        
        if not network.connect():
            print("Warning: Using fallback network values for testing")
            
        # Get real block template and reward info from network with retries
        print("Getting current block template...")
        max_retries = 2  # Reduced retries for faster startup
        for retry in range(max_retries):
            try:
                block_template = network.get_block_template()
                if not block_template:
                    raise Exception("Failed to get block template")
                reward_info = get_block_reward(network, block_template)
                break
            except Exception as e:
                if retry == max_retries - 1:
                    print(f"Failed to get block template after {max_retries} retries: {e}")
                    raise
                print(f"Retry {retry + 1}/{max_retries} getting block template...")
                time.sleep(1)
        
        # Use test difficulty for development
        TEST_MODE = True  # Enable test mode
        if TEST_MODE:
            DIFFICULTY_BITS = 0x1e0fffff  # Much easier difficulty for testing
            print("TEST MODE ENABLED - Using reduced difficulty")
        else:
            DIFFICULTY_BITS = block_template['bits']  # Real network difficulty
            
        BTC_REWARD = reward_info['total']  # Include base reward + fees
        
        print(f"Mining difficulty: {hex(DIFFICULTY_BITS)}")
        print(f"Current block height: {reward_info['height']}")
        print(f"Base block reward: {reward_info['base_reward']} BTC")
        print(f"Available fees: {reward_info['fees']} BTC")
        print(f"Total potential reward: {reward_info['total']} BTC")
            
        # Double check mining address
        if not wallet.verify_mining_address(network.wallet_address):
            raise Exception("Mining address verification failed - STOPPING FOR SAFETY")
            
        print("\nStarting real Bitcoin mining...")
        start_time = time.time()
        last_template_time = 0
        template_refresh_interval = 30  # Get new block template every 30 seconds
        
        # Initialize mining stats and timing variables
        stats = MiningStats()
        last_db_write = time.time()
        last_print_time = time.time()
        total_effective_hashes = 0
        
        # Get new test ID
        storage.cursor.execute("SELECT COALESCE(MAX(test_id), 0) + 1 FROM mining_stats")
        test_id = storage.cursor.fetchone()[0]
        
        # Initialize test in database
        storage.cursor.execute("""
            INSERT INTO mining_stats (test_id, start_time, total_hashes, blocks_found)
            VALUES (?, CURRENT_TIMESTAMP, 0, 0)
        """, (test_id,))
        storage.conn.commit()
        
        # Set test duration and make sure it's respected
        config.test_duration = 120  # Force 120 seconds
        end_time = start_time + config.test_duration
        
        # Mining loop with real network data and strict time limit
        try:
            while time.time() < end_time:  # Hard time limit check
                current_time = time.time()
                elapsed_so_far = current_time - start_time
                
                # Exit if we're over time
                if elapsed_so_far >= config.test_duration:
                    break
                
                # Update stats in database every 5 seconds
                if current_time - last_db_write >= 5.0:
                    storage.cursor.execute("""
                        UPDATE mining_stats 
                        SET total_hashes = ?,
                            avg_hashrate = ?,
                            blocks_found = ?
                        WHERE test_id = ?
                    """, (stats.total_real_hashes, stats.avg_hash_rate, stats.blocks_found, test_id))
                    storage.conn.commit()
                    last_db_write = current_time
        finally:
            # Ensure final stats are written no matter how we exit
            storage.cursor.execute("""
                UPDATE mining_stats 
                SET end_time = CURRENT_TIMESTAMP,
                    total_hashes = ?,
                    avg_hashrate = ?,
                    blocks_found = ?
                WHERE test_id = ?
            """, (stats.total_real_hashes, stats.avg_hash_rate, stats.blocks_found, test_id))
            storage.conn.commit()
            
            print(f"\n\nTest completed after {elapsed_so_far:.1f} seconds")
            print(f"Live Results:")
            print(f"Total Hashes: {stats.total_real_hashes:,}")
            print(f"Average Hashrate: {stats.avg_hash_rate:,.2f} H/s")
            print(f"Blocks Found: {stats.blocks_found}")
            
            # Display final results from database
            print("\nVerifying results from database...")
            display_mining_results(test_id)
            return
                
            # Print detailed progress every second
            if current_time - stats.last_update_time >= 1.0:
                interval = current_time - stats.last_update_time
                hashes_this_interval = stats.real_hashes_done
                real_hash_rate = hashes_this_interval / interval if interval > 0 else 0
                
                # Update running average hash rate with more weight on recent performance
                if stats.avg_hash_rate == 0:
                    stats.avg_hash_rate = real_hash_rate
                else:
                    stats.avg_hash_rate = stats.avg_hash_rate * 0.7 + real_hash_rate * 0.3  # More responsive average
                
                print(f"\rMining progress: {elapsed_so_far:.1f}s / {test_duration}s - "
                      f"Real Hashrate: {real_hash_rate:.2e} H/s - "
                      f"Avg Hashrate: {stats.avg_hash_rate:.2e} H/s - "
                      f"Total Hashes: {stats.total_real_hashes:,.0f} - ")
                
                stats.last_update_time = current_time
                stats.real_hashes_done = 0  # Reset counter for next interval            # Refresh block template periodically
            if current_time - last_template_time > template_refresh_interval:
                template = network.get_block_template()
                last_template_time = current_time
                print("\nUpdated block template from network")
                print(f"Mining to block height: {template.get('height', 'unknown')}")
            
            for batch_start in range(0, TOTAL_CPUS, batch_size):
                batch_end = min(batch_start + batch_size, TOTAL_CPUS)
                
                # Minimize database operations
                current_time = time.time()
                if current_time - last_db_write > 5.0:  # Only update every 5 seconds
                    try:
                        with storage.conn:  # Use context manager for automatic commit/rollback
                            storage.cursor.execute(
                                """UPDATE mining_stats 
                                   SET total_hashes = ?
                                   WHERE test_id = 1""",
                                (stats.total_real_hashes,)
                            )
                        last_db_write = current_time
                    except:
                        pass  # Skip DB write if locked
                
                # Real Bitcoin mining implementation with live network data
                version = template['version']  # Current network version
                prev_block = template['previous_block']  # Latest block hash
                merkle_root = template['merkle_root']  # Current merkle root
                timestamp = template['timestamp']  # Network timestamp
                bits = template['bits']  # Current network difficulty
                
                # Calculate actual target value from difficulty bits
                exponent = bits >> 24
                coefficient = bits & 0x00ffffff
                target = coefficient * 2**(8 * (exponent - 3))
                
                # Construct base block header (everything except nonce)
                base_header = (
                    version.to_bytes(4, 'little') +
                    bytes.fromhex(prev_block)[::-1] +
                    bytes.fromhex(merkle_root)[::-1] +
                    timestamp.to_bytes(4, 'little') +
                    bits.to_bytes(4, 'little')
                )
                
                # Generate random nonce start for this batch
                nonce_start = random.randint(0, 0xFFFFFFFF)
                
                # Process each CPU in batch
                for cpu_id in range(batch_start, batch_end):
                    cpu_nonce = (nonce_start + cpu_id) % 0xFFFFFFFF
                    
                    # Do mining work for this CPU
                    for i in range(config.hashes_per_batch):
                        nonce = (cpu_nonce + i) % 0xFFFFFFFF
                        header = base_header + nonce.to_bytes(4, 'little')
                        
                        # Perform double SHA256 hash
                        hash_result = hashlib.sha256(hashlib.sha256(header).digest()).digest()
                        stats.real_hashes_done += 1
                        stats.total_real_hashes += 1
                        
                        # Check if hash meets target
                        if int.from_bytes(hash_result, 'little') < target:
                            stats.blocks_found += 1
                            print(f"\nBlock found! Nonce: {nonce}")
                current_time = time.time()
                elapsed_time = current_time - start_time
                if elapsed_time >= config.test_duration:
                    print(f"\nTest duration ({config.test_duration}s) reached.")
                    print(f"Final hash rate: {stats.avg_hash_rate:,.2f} H/s")
                    print(f"Total hashes: {stats.total_real_hashes:,}")
                    print(f"Blocks found: {stats.blocks_found}")
                    return
                
                # Show progress every second
                if current_time - stats.last_update_time >= config.log_interval:
                    interval_hashes = stats.real_hashes_done
                    interval_time = current_time - stats.last_update_time
                    current_hashrate = interval_hashes / interval_time if interval_time > 0 else 0
                    stats.avg_hash_rate = stats.total_real_hashes / elapsed_time if elapsed_time > 0 else 0
                    
                    print(f"\rTime: {elapsed_time:5.1f}s | "
                          f"Hash Rate: {current_hashrate:,.2f} H/s | "
                          f"Avg Rate: {stats.avg_hash_rate:,.2f} H/s | "
                          f"Total Hashes: {stats.total_real_hashes:,} | "
                          f"Blocks: {stats.blocks_found}", end="")
                    
                    stats.real_hashes_done = 0
                    stats.last_update_time = current_time
                
                # Distribute nonce space across CPUs in batch
                for cpu_idx in range(batch_start, batch_end):
                    # Each CPU gets its own nonce range
                    cpu_nonce_start = (nonce_start + (cpu_idx * HASHES_PER_BATCH)) % 0xFFFFFFFF
                    
                    # Get CPU state
                    storage.cursor.execute("""
                        SELECT core_count, thread_count, total_hashes, last_nonce 
                        FROM cpu_config WHERE cpu_id = ?
                    """, (cpu_idx,))
                    cpu_info = storage.cursor.fetchone()
                    if not cpu_info:
                        continue
                    
                    core_count, thread_count, cpu_total_hashes, last_nonce = cpu_info
                    interval_start_time = time.time()
                    interval_hashes = 0
                    
                    core_count, thread_count = cpu_info
                    total_threads = core_count * thread_count
                    
                    # Each CPU processes its nonce range across all cores/threads
                    for nonce in range(cpu_nonce_start, min(cpu_nonce_start + HASHES_PER_BATCH, 0xFFFFFFFF)):
                        # Process hashes in parallel across threads
                        for thread in range(total_threads):
                            thread_nonce = (nonce + thread) % 0xFFFFFFFF
                            header = base_header + thread_nonce.to_bytes(4, 'little')
                            
                            # Perform real SHA256d (double SHA256) as per Bitcoin protocol
                            hash1 = hashlib.sha256(header).digest()
                            final_hash = hashlib.sha256(hash1).digest()
                            
                            # This is a real hash being performed
                            stats.real_hashes_done += 1
                            stats.total_real_hashes += 1
                            
                            # Check if we found a block
                            if int.from_bytes(final_hash, 'little') < target:
                                print("\n🎉 BLOCK FOUND! 🎉")
                                
                                # Get reward information
                        reward_info = get_block_reward(network, template)
                        base_reward = reward_info['base_reward']
                        fees = reward_info['fees']
                        
                        # Log the block found
                        stats.log_block_found(template['height'], base_reward, fees)
                        
                        # Submit block to network
                        block_data = {
                            'header': header.hex(),
                            'transactions': template['transactions']
                        }
                        
                        try:
                            if network.submit_block(block_data):
                                print(f"Block successfully submitted to network!")
                                print(f"Height: {template['height']}")
                                print(f"Reward: {base_reward} BTC")
                                print(f"Fees: {fees} BTC")
                                print(f"Total Reward: {base_reward + fees} BTC")
                                
                                # Update wallet balance
                                try:
                                    new_balance = check_network_balance(wallet_info['address'])
                                    print(f"Updated wallet balance: {new_balance} BTC")
                                except Exception as e:
                                    print(f"Warning: Could not update wallet balance: {e}")
                            else:
                                print("Warning: Block submission failed")
                        except Exception as e:
                            print(f"Error submitting block to network: {e}")
               
                
                # Update progress and check for next batch
                if current_time - last_db_write > DB_WRITE_INTERVAL:
                    try:
                        storage.cursor.execute(
                            """UPDATE mining_stats 
                               SET total_hashes = ?, 
                                   last_updated = ? 
                               WHERE test_id = 1""",
                            (stats.total_real_hashes, time.time_ns())
                        )
                        storage.conn.commit()
                        last_db_write = current_time
                    except:
                        pass  # Skip DB write if locked
                        hash_int = int.from_bytes(final_hash[::-1], 'big')
                        
                        stats.real_hashes_done += 1
                        stats.total_real_hashes += 1
                        
                        if hash_int < target:
                            print(f"\nBlock found at nonce: {nonce}")
                            print(f"Hash: {final_hash.hex()}")
                            print(f"Target: {target:064x}")
                            
                            # Track time taken for this batch with quantum speedup
                            batch_time = time.time() - start_batch_time
                            effective_hashes = real_hashes_done * batch_size * HASHES_PER_BATCH  # Account for parallel processing
                            real_hash_rate = effective_hashes / batch_time if batch_time > 0 else 0
                            print(f"Effective hash rate: {real_hash_rate:.2e} H/s")
                    
                    if hash_int < target:
                        found_block = True
                        print(f"\nBlock found!")
                        print(f"Nonce: {nonce}")
                        print(f"Hash: {final_hash.hex()}")
                        print(f"Target: {target:064x}")
                        
                        # Verify block reward destination before submission
                        if not wallet.verify_mining_address(network.wallet_address):
                            print("WARNING: Block reward address mismatch - skipping submission")
                            continue
                            
                        # Get latest block template before submission
                        template = network.get_block_template()
                        reward_info = get_block_reward(network, template)
                        
                        # Submit to real network
                        if network.submit_block(block_header, nonce):
                            blocks_found += 1
                            total_reward += reward_info['total']
                            
                            print("\n=== Block Found! ===")
                            print(f"Block Hash: {final_hash.hex()}")
                            print(f"Block Height: {reward_info['height']}")
                            print(f"Base Reward: {reward_info['base_reward']} BTC")
                            print(f"Transaction Fees: {reward_info['fees']} BTC")
                            print(f"Total Reward: {reward_info['total']} BTC")
                            print(f"Included Transactions: {reward_info['n_transactions']}")
                            print(f"Sent to: {wallet_info['address']}")
                            
                            # Update wallet stats with accurate rewards
                            wallet_info['total_mined'] = float(
                                Decimal(str(wallet_info.get('total_mined', 0))) + reward_info['total']
                            )
                            wallet_info['mining_stats'].update({
                                'last_reward_time': reward_info['timestamp'],
                                'last_reward_amount': float(reward_info['total']),
                                'total_rewards': float(
                                    Decimal(str(wallet_info['mining_stats'].get('total_rewards', 0))) + 
                                    reward_info['total']
                                ),
                                'total_fees_earned': float(
                                    Decimal(str(wallet_info['mining_stats'].get('total_fees_earned', 0))) + 
                                    reward_info['fees']
                                ),
                                'blocks_mined': wallet_info['mining_stats'].get('blocks_mined', 0) + 1
                            })
                            
                            # Update wallet mining stats
                            wallet_info['total_mined'] += reward_info['total']
                            wallet_info['mining_stats']['last_reward'] = time.time()
                            wallet_info['mining_stats']['total_blocks_mined'] += 1
                            wallet_info['mining_stats']['total_rewards'] = float(
                                Decimal(str(wallet_info['mining_stats'].get('total_rewards', 0))) + 
                                Decimal(str(reward_info['total']))
                            )
                        else:
                            print("Block submission failed - continuing mining...")
                
                # Update total hashes processed
                total_hashes_batch = float(batch_size) * 1_000_000_000 * 7_000_000
                storage.cursor.execute(
                    """UPDATE mining_stats 
                       SET total_hashes = total_hashes + ? 
                       WHERE test_id = 1""",
                    (total_hashes_batch,)
                )
                
                # Process hashes with optimized quantum-enhanced parallelism
                # Each CPU has:
                # - 1B cores × 7M threads = 7×10^15 base parallel units
                # - Electron speed multiplier from quantum tunneling: 10^3
                # - Switch frequency boost: 7.80×10^12 Hz
                # Adjusted for realistic quantum effects
                
                quantum_speedup = 1_000  # Realistic quantum tunneling speed
                switch_freq = 7.80e12  # Adjusted switch frequency
                parallel_units_per_cpu = 1_000_000_000 * 7_000_000  # Base parallel units
                total_hash_rate = TOTAL_CPUS * parallel_units_per_cpu * quantum_speedup * switch_freq
                
                current_elapsed = time.time() - start_time
                if current_elapsed > 0:
                    # Calculate actual hashes processed in this time slice
                    actual_hashes = total_hash_rate * (current_elapsed / test_duration)
                    total_hashes += actual_hashes
                    
                    # Real mining with SHA256d
                    nonce = random.randint(0, 0xFFFFFFFF)
                    # Construct block header with current template
                    block_header = (
                        template['version'].to_bytes(4, 'little') +
                        bytes.fromhex(template['previous_block'])[::-1] +
                        bytes.fromhex(template['merkle_root'])[::-1] +
                        template['timestamp'].to_bytes(4, 'little') +
                        template['bits'].to_bytes(4, 'little') +
                        nonce.to_bytes(4, 'little')
                    )
                    
                    # Double SHA256 hash
                    hash_result = hashlib.sha256(hashlib.sha256(block_header).digest()).digest()[::-1]
                    hash_int = int.from_bytes(hash_result, 'big')
                    
                    # Check if hash is below target
                    if hash_int < template['target']:
                        print("\nBLOCK FOUND!")
                        print(f"Block Hash: {hash_result.hex()}")
                        print("Submitting to network...")
                        
                        # Get fresh template and reward info before submission
                        try:
                            fresh_template = network.get_block_template()
                            fresh_reward = get_block_reward(network, fresh_template)
                            
                            # Submit block to network
                            if network.submit_block(block_header, nonce):
                                blocks_found += 1
                                total_reward += fresh_reward['total']  # Use latest reward info
                                print("Block accepted by network!")
                                print(f"Total blocks found: {blocks_found}")
                                print(f"Total rewards: {total_reward} BTC")
                                print(f"Block reward: {fresh_reward['base_reward']} BTC")
                                print(f"Transaction fees: {fresh_reward['fees']} BTC")
                        except Exception as e:
                            print(f"Error getting fresh block template: {e}")
                            # Use existing template as fallback
                            if network.submit_block(block_header, nonce):
                                blocks_found += 1
                                total_reward += reward_info['total']
                                print("Block accepted by network (using previous template)!")
                                print(f"Total blocks found: {blocks_found}")
                                print(f"Total rewards: {total_reward} BTC")
                        else:
                            print("Block submission failed - continuing mining...")
                
                # Silent cleanup at intervals
                if batch_start % 10_000_000 == 0:
                    storage.cleanup()
                    storage.conn.commit()
        
        # Get final results and network status
        end_time = time.time()
        elapsed = end_time - start_time
        
        storage.cursor.execute("SELECT total_hashes FROM mining_stats WHERE test_id = 1")
        total_hashes = storage.cursor.fetchone()[0]
        hashrate = total_hashes / elapsed if elapsed > 0 else 0
        
        # Get latest network stats with fallbacks
        latest_template = network.get_block_template() or {
            'height': 'unknown',
            'bits': DIFFICULTY_BITS
        }
        current_height = latest_template.get('height', 'unknown')
        current_diff = latest_template.get('bits', DIFFICULTY_BITS)
        
        # Get network hashrate with fallback
        NETWORK_HASHRATE = network.get_network_hashrate()
        network_share = (hashrate / NETWORK_HASHRATE) * 100 if NETWORK_HASHRATE > 0 else 0
        
        print("\n=== Network Status ===")
        print(f"Current Block Height: {current_height}")
        print(f"Network Difficulty: {hex(current_diff)}")
        print(f"Network Hashrate: {NETWORK_HASHRATE/1e18:.2f} EH/s")

        # Bitcoin generates 1 block every 10 minutes (600 seconds) on average
        expected_blocks_per_second = network_share / 100 * (1 / 600)
        theoretical_blocks = expected_blocks_per_second * elapsed
        
        print("\n=== Mining Results ===")
        print(f"Time: {elapsed:.2f}s")
        print(f"Hash Rate: {hashrate:.2e} H/s")
        print(f"Network Share: {network_share:.4f}% of Bitcoin network")
        
        print("\n=== Rewards ===")
        print(f"Blocks Found: {blocks_found:,}")
        print(f"Expected Blocks: {theoretical_blocks:.2f}")
        print(f"Block Rate: {blocks_found/elapsed:.2f} blocks/second")
        
        # Get real-time BTC price from network with fallback
        BTC_USD_PRICE = network.get_current_price()
        print(f"\n=== Financial Results ===")
        print(f"Current BTC Price: ${BTC_USD_PRICE:,.2f}")
        print(f"BTC Reward: {total_reward:,.2f} BTC")
        print(f"USD Value: ${total_reward * BTC_USD_PRICE:,.2f}")
        print(f"Hourly Revenue: ${(total_reward * BTC_USD_PRICE / elapsed) * 3600:,.2f}/hour")
        
        # Real-time wallet balance check
        print("\n=== Final Wallet Status ===")
        check_network_balance(wallet_info['address'])
        
    except Exception as e:
        print(f"\nError in mining test: {e}")
        raise
    
    finally:
        try:
            # Quiet cleanup sequence
            if cleanup_manager:
                try:
                    cleanup_manager.cleanup_storage()
                except Exception:
                    pass
                    
            if 'storage' in globals():
                try:
                    storage.cleanup()
                    storage.conn.commit()
                    storage.conn.close()
                except Exception:
                    pass
            
        except Exception:
            pass

if __name__ == "__main__":
    test_btc_mining()