import hashlib
import json
import time
from typing import List, Dict
import logging

logger = logging.getLogger(__name__)

class Block:
    def __init__(self, index: int, timestamp: float, transactions: List[Dict], previous_hash: str):
        self.index = index
        self.timestamp = timestamp
        self.transactions = transactions
        self.previous_hash = previous_hash
        self.hash = self.calculate_hash()
    
    def calculate_hash(self) -> str:
        """Calcola hash del blocco"""
        block_string = json.dumps({
            'index': self.index,
            'timestamp': self.timestamp,
            'transactions': self.transactions,
            'previous_hash': self.previous_hash
        }, sort_keys=True)
        return hashlib.sha256(block_string.encode()).hexdigest()

class Blockchain:
    def __init__(self):
        self.chain: List[Block] = [self.create_genesis_block()]
        self.pending_transactions: List[Dict] = []
        self.mining_reward = 10
        self.difficulty = 2
        self.total_requests = 0
    
    def create_genesis_block(self) -> Block:
        """Crea blocco genesis"""
        return Block(0, time.time(), [], "0")
    
    def get_latest_block(self) -> Block:
        """Ottiene ultimo blocco"""
        return self.chain[-1]
    
    def record_contribution(self, worker_id: str, work_units: int):
        """Registra contributo di lavoro per ricompensa"""
        reward = work_units * 0.1  # Ricompensa proporzionale
        
        transaction = {
            'type': 'contribution_reward',
            'worker_id': worker_id,
            'work_units': work_units,
            'reward': reward,
            'timestamp': time.time()
        }
        
        self.pending_transactions.append(transaction)
        self.total_requests += 1
        
        logger.info(f"Recorded contribution: {worker_id} - {work_units} units - {reward} reward")
        
        # Mining semplificato - in produzione usare algoritmo vero
        if len(self.pending_transactions) >= 10:
            self.mine_pending_transactions()
    
    def mine_pending_transactions(self):
        """Mina le transazioni pendenti (versione semplificata)"""
        if not self.pending_transactions:
            return
        
        block = Block(
            len(self.chain),
            time.time(),
            self.pending_transactions,
            self.get_latest_block().hash
        )
        
        self.chain.append(block)
        self.pending_transactions = []
        
        logger.info(f"Mined block {block.index} with {len(block.transactions)} transactions")
    
    def get_worker_balance(self, worker_id: str) -> float:
        """Calcola balance totale di un worker"""
        balance = 0.0
        for block in self.chain:
            for transaction in block.transactions:
                if (transaction.get('type') == 'contribution_reward' and 
                    transaction.get('worker_id') == worker_id):
                    balance += transaction.get('reward', 0)
        return balance
    
    def get_total_requests(self) -> int:
        """Restituisce il numero totale di richieste processate"""
        return self.total_requests
    
    def get_total_rewards_distributed(self) -> float:
        """Calcola il totale delle ricompense distribuite"""
        total_rewards = 0.0
        for block in self.chain:
            for transaction in block.transactions:
                if transaction.get('type') == 'contribution_reward':
                    total_rewards += transaction.get('reward', 0)
        return total_rewards
    
    def get_worker_stats(self, worker_id: str) -> Dict:
        """Restituisce statistiche per un worker specifico"""
        contributions = 0
        total_reward = 0.0
        
        for block in self.chain:
            for transaction in block.transactions:
                if (transaction.get('type') == 'contribution_reward' and 
                    transaction.get('worker_id') == worker_id):
                    contributions += 1
                    total_reward += transaction.get('reward', 0)
        
        return {
            'worker_id': worker_id,
            'contributions': contributions,
            'total_reward': total_reward,
            'balance': self.get_worker_balance(worker_id)
        }
    
    def get_system_stats(self) -> Dict:
        """Restituisce statistiche complete del sistema"""
        total_workers = set()
        total_contributions = 0
        
        for block in self.chain:
            for transaction in block.transactions:
                if transaction.get('type') == 'contribution_reward':
                    total_workers.add(transaction.get('worker_id'))
                    total_contributions += 1
        
        return {
            'total_blocks': len(self.chain),
            'total_transactions': sum(len(block.transactions) for block in self.chain),
            'total_workers': len(total_workers),
            'total_contributions': total_contributions,
            'total_requests': self.total_requests,
            'total_rewards': self.get_total_rewards_distributed(),
            'pending_transactions': len(self.pending_transactions)
        }
    
    def is_chain_valid(self) -> bool:
        """Verifica validità della blockchain"""
        for i in range(1, len(self.chain)):
            current_block = self.chain[i]
            previous_block = self.chain[i-1]
            
            if current_block.hash != current_block.calculate_hash():
                return False
            if current_block.previous_hash != previous_block.hash:
                return False
        
        return True