import hashlib
import time

class Block:
  def __init__(self, index, data, previous_hash, timestamp=None):
    self.index = index
    self.timestamp = timestamp or time.time()
    self.data = data
    self.previous_hash = previous_hash
    self.nonce = 0
    self.hash = self.compute_proof_of_work()

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

  def compute_proof_of_work(self, difficulty=3):
    prefix = '0' * difficulty
    while True:

      hash_result = self.compute_hash()
      if hash_result.startswith(prefix):
        return hash_result
      self.nonce += 1

class Blockchain:
  def __init__(self):
    self.chain = [self.create_genesis_block()]
    self.difficulty = 3

  def create_genesis_block(self):
    return Block(0, "Genesis Block", "0")

  def add_block(self, data):
    previous = self.chain[-1]
    new_block = Block(len(self.chain), data, previous.hash)
    self.chain.append(new_block)

  def is_valid_chain(self, chain):
    for i in range(1, len(chain)):
      current = chain[i]
      previous = chain[i - 1]
      if current.previous_hash != previous.hash or \
        current.hash != current.compute_hash():
        return False
    return True

  def replace_chain(self, other_chains):
    longest_chain = self.chain
    for chain in other_chains:

      if len(chain) > len(longest_chain) and self.is_valid_chain(chain):
        longest_chain = chain
    self.chain = longest_chain

  def display(self):
    for block in self.chain:
      print(f"Block {block.index} | Hash: {block.hash}")
      print(f"Data: {block.data}")
      print(f"Nonce: {block.nonce}")
      print(f"Previous Hash: {block.previous_hash}\n")

# --- Simulate Multiple Nodes and Consensus ---
if __name__ == "__main__":
# Create multiple blockchains (nodes)
  node_A = Blockchain()
  node_B = Blockchain()
  node_C = Blockchain()

  # Each node adds blocks
  node_A.add_block("A1")
  node_A.add_block("A2")

  node_B.add_block("B1")

  node_C.add_block("C1")
  node_C.add_block("C2")
  node_C.add_block("C3")

  print("\nBefore Consensus:")
  print("Node A Chain Length:", len(node_A.chain))

  print("Node B Chain Length:", len(node_B.chain))
  print("Node C Chain Length:", len(node_C.chain))

  # Apply consensus: Node A syncs with longest chain
  node_A.replace_chain([node_B.chain, node_C.chain])

  print("\nAfter Consensus (Node A):")
  node_A.display()