"""
Resource-optimized SHA256 mining system with SQLite storage and 60s timeout
"""

import time
import hashlib
import sqlite3
from quantum_parallel_driver import QuantumParallelDriver
from virtual_cpu import DEFAULT_NUM_CORES, THREADS_PER_CORE
import threading
import signal
import os
from multiprocessing import Value, Array, Lock
import signal
import sys

class BenchmarkMiner:
    def __init__(self):
        # Use fewer cores but keep them fully utilized
        self.num_cores = 8  # Reduced for stability
        self.threads_per_core = 4  # Reduced thread count
        self.driver = QuantumParallelDriver(num_cores=self.num_cores)
        self.running = True
        self.batch_size = 1000  # Smaller batches for better memory usage
        self.start_time = None
        self.last_log_time = None
        self.setup_database()
        
    def setup_database(self):
        """Setup SQLite database for storing results"""
        self.db_path = 'mining_results.db'
        conn = sqlite3.connect(self.db_path)
        c = conn.cursor()
        c.execute('''CREATE TABLE IF NOT EXISTS hash_counts 
                    (timestamp REAL, count INTEGER)''')
        c.execute('''CREATE TABLE IF NOT EXISTS hash_rates
                    (timestamp REAL, rate REAL)''')
        conn.commit()
        conn.close()
        
    def prepare_mining_data(self):
        """Prepare memory-efficient mining batch"""
        instructions = []
        timestamp = int(time.time() * 1000).to_bytes(8, 'big')
        
        for i in range(self.batch_size):
            # Use deterministic nonce instead of random
            nonce = i.to_bytes(32, 'big')
            instruction = {
                'type': 'SHA256',
                'vector_offset': i * 40,
                'size': 40,
                'data': nonce + timestamp,
                'core_id': i % self.num_cores,
                'thread_id': (i // self.num_cores) % self.threads_per_core
            }
            instructions.append(instruction)
        return instructions
        
    def signal_handler(self, signum, frame):
        """Handle Ctrl+C gracefully"""
        self.running = False
        print("\nStopping gracefully...")
        
    def log_progress(self):
        """Log progress every second"""
        current_time = time.time()
        elapsed = current_time - self.start_time
        
        if self.last_log_time is None or (current_time - self.last_log_time) >= 1.0:
            total_hashes = self.get_total_hashes()
            hash_rate = total_hashes / elapsed
            
            print(f"[{elapsed:.1f}s] Hashes: {total_hashes:,} | Rate: {hash_rate:,.2f} H/s", end='\r')
            sys.stdout.flush()
            
            # Log rate to database
            conn = sqlite3.connect(self.db_path)
            c = conn.cursor()
            c.execute('INSERT INTO hash_rates VALUES (?, ?)', 
                     (current_time, hash_rate))
            conn.commit()
            conn.close()
            
            self.last_log_time = current_time

    def log_hash_count(self, count):
        """Log hash count to SQLite"""
        conn = sqlite3.connect(self.db_path)
        c = conn.cursor()
        c.execute('INSERT INTO hash_counts VALUES (?, ?)', 
                 (time.time(), count))
        conn.commit()
        conn.close()
        
    def get_total_hashes(self):
        """Get total hashes from SQLite"""
        conn = sqlite3.connect(self.db_path)
        c = conn.cursor()
        c.execute('SELECT SUM(count) FROM hash_counts')
        total = c.fetchone()[0] or 0
        conn.close()
        return total

    def start_benchmark(self):
        """Run benchmark for exactly 60 seconds"""
        self.start_time = time.time()
        end_time = self.start_time + 60
        
        print(f"\nStarting 60-second benchmark with {self.num_cores} cores and {self.threads_per_core} threads per core")
        print("Processing with SQLite storage for minimal RAM usage\n")
        
        try:
            while time.time() < end_time and self.running:
                instructions = self.prepare_mining_data()
                self.driver.execute(instructions)
                self.log_hash_count(len(instructions))
                self.log_progress()
                
        except KeyboardInterrupt:
            print("\nStopped by user.")
        finally:
            self.print_final_results()
            self.cleanup()
            
    def print_final_results(self):
        """Print final benchmark results"""
        total_time = time.time() - self.start_time
        total_hashes = self.get_total_hashes()
        hash_rate = total_hashes / total_time
        
        print("\n\n=== Final Benchmark Results ===")
        print(f"Total Runtime: {total_time:.2f} seconds")
        print(f"Total Hashes: {total_hashes:,}")
        print(f"Average Hash Rate: {hash_rate:,.2f} H/s")
        print(f"Configuration: {self.num_cores} cores × {self.threads_per_core} threads")
        print(f"Total Threads: {self.num_cores * self.threads_per_core}")
        print("=============================")
        
    def cleanup(self):
        """Cleanup resources"""
        self.driver.stop()
        try:
            os.remove(self.db_path)
        except:
            pass

if __name__ == "__main__":
    miner = BenchmarkMiner()
    miner.start_benchmark()