import hashlib, time

# ---------------------------
# Block class
# ---------------------------
class Block:
    def __init__(self, index, data, prev_hash):
        self.index = index
        self.timestamp = time.time()
        self.data = data
        self.prev_hash = prev_hash
        self.nonce = 0  # Initialize nonce before computing hash
        self.hash = self.compute_hash()

    def compute_hash(self):
        content = f"{self.index}{self.timestamp}{self.data}{self.prev_hash}{self.nonce}"
        return hashlib.sha256(content.encode()).hexdigest()

    def mine(self, difficulty):
        while not self.hash.startswith("0" * difficulty):
            self.nonce += 1
            self.hash = self.compute_hash()

# ---------------------------
# Blockchain class
# ---------------------------
class Blockchain:
    def __init__(self, difficulty=2):
        self.difficulty = difficulty
        self.chain = [Block(0, "Genesis Block", "0")]

    def last_block(self): return self.chain[-1]

    def add_block(self, data):
        new_block = Block(len(self.chain), data, self.last_block().hash)
        new_block.mine(self.difficulty)
        self.chain.append(new_block)

    def is_valid(self):
        for i in range(1, len(self.chain)):
            cur, prev = self.chain[i], self.chain[i-1]
            if cur.hash != cur.compute_hash() or cur.prev_hash != prev.hash:
                return False
        return True

# ---------------------------
# Client class
# ---------------------------
class Client:
    def __init__(self, name, blockchain):
        self.name, self.blockchain = name, blockchain

    def transact(self, msg):
        print(f"\n[{self.name}] Transaction: {msg}")
        self.blockchain.add_block(f"{self.name}: {msg}")

# ---------------------------
# Main
# ---------------------------
if __name__ == "__main__":
    bc = Blockchain()

    # Clients
    alice, bob, charlie = Client("Alice", bc), Client("Bob", bc), Client("Charlie", bc)

    # Transactions
    alice.transact("Sent 5 BTC to Bob")
    bob.transact("Sent 2 BTC to Charlie")
    charlie.transact("Received 3 BTC from Alice")

    # Print chain
    print("\nBlockchain:")
    for b in bc.chain:
        print(f"\nBlock {b.index} | Data: {b.data}\nHash: {b.hash}\nPrev: {b.prev_hash}")

    print("\nIs Blockchain Valid?", bc.is_valid())