import hashlib
import time

class Block:
    def __init__(self, index, previous_hash, timestamp, data, nonce=0):
        self.index = index
        self.previous_hash = previous_hash
        self.timestamp = timestamp
        self.data = data
        self.nonce = nonce
        self.hash = self.calculate_hash()

    def calculate_hash(self):
        block_string = (str(self.index) + self.previous_hash +
                        str(self.timestamp) + str(self.data) +
                        str(self.nonce))
        return hashlib.sha256(block_string.encode()).hexdigest()


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

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

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

    def mine_block(self, data):
        index = len(self.chain)
        previous_hash = self.get_latest_block().hash
        timestamp = int(time.time())
        nonce = 0

        new_block = Block(
            index, previous_hash, timestamp, data, nonce
        )

        while not self.is_valid_proof(new_block):
            nonce += 1
            new_block.nonce = nonce
            new_block.hash = new_block.calculate_hash()

        self.chain.append(new_block)

    def is_valid_proof(self, block):
        target = "0" * self.difficulty
        return block.hash[:self.difficulty] == target

    def is_chain_valid(self):
        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

            if not self.is_valid_proof(current_block):
                return False

        return True


# Create blockchain
my_blockchain = Blockchain()

print("Mining Block 1...")
my_blockchain.mine_block("Block 1 Data")

print("Mining Block 2...")
my_blockchain.mine_block("Block 2 Data")

# Display blockchain
print("\nBlockchain:")

for block in my_blockchain.chain:
    print(
        f"Block #{block.index} - "
        f"Hash: {block.hash} - "
        f"Data: {block.data} - "
        f"Nonce: {block.nonce}"
    )

print(
    f"\nIs blockchain valid? "
    f"{my_blockchain.is_chain_valid()}"
)