from flask import Flask, request
import time
import requests
import json

from blockchain import Blockchain
from block import Block

app = Flask(__name__)

blockchain = Blockchain()

peers = set()

@app.route('/add_nodes', methods=['POST'])
def register_new_peers():
    nodes = request.get_json()
    if not nodes:
        return "Invalid data", 400
    
    for node in nodes:
        peers.add(node)

    return "Success", 201

@app.route('/new_transaction', methods=['POST'])
def new_transaction():
    tx_data = request.get_json()
    required_fields = ["author", "content"]

    for field in required_fields:
        if not tx_data.get(field):
            return "Invalid transaction data", 404

    tx_data["timestamp"] = time.time()
    blockchain.add_new_transaction(tx_data)
    return "Sucess", 201

@app.route('/chain', methods=['GET'])
def get_chain():
    chain_data = []
    for block in blockchain.chain:
        chain_data.append(block.__dict__)
    return json.dumps({ "length": len(chain_data), "chain": chain_data })

@app.route('/mine', methods=['GET'])
def mine_unconfirmed_transactions():
    result = blockchain.mine()
    if not result:
        return "No transactions to mine"
    return "Block #{} is mined.".format(result)

@app.route('/pending_tx')
def get_pending_tx():
    return json.dumps(blockchain.unconfirmed_transactions)

def consensus():
    global blockchain

    longest_chain = None
    current_len = len(blockchain)

    for node in peers:
        response = requests.get('http://{}/chain'.format(node))
        length = response.json()['length']
        chain = response.json()['chain']
        if length > current_len and blockchain.check_chain_validity(chain):
            current_len = length
            longest_chain = chain

    if longest_chain:
        blockchain = longest_chain
        return True

    return False

@app.route('/add_block', methods=['POST'])
def validate_and_add_block():
    block_data = request.get_json()
    block = Block(block_data["index"], block_data["transactions"], block_data["timestamp", block_data["previous_hash"]])

    proof = block_data['hash']
    added = blockchain.add_block(block, proof)

    if not added:
        return "The block was discarded by the node", 400

    return "Block added to the chain", 201

def announce_new_block(block):
    for peer in peers:
        url = "http://{}/add_block".format(peer)
        requests.post(url, data=json.dumps(block.__dict__, sort_keys=True))


app.run(debug=True, port=8000)

[((9, 6, 9, 21), 'flask.Flask', 'Flask', ({(9, 12, 9, 20): '__name__'}, {}), '(__name__)', False, 'from flask import Flask, request\n'), ((11, 13, 11, 25), 'blockchain.Blockchain', 'Blockchain', ({}, {}), '()', False, 'from blockchain import Blockchain\n'), ((17, 12, 17, 30), 'flask.request.get_json', 'request.get_json', ({}, {}), '()', False, 'from flask import Flask, request\n'), ((28, 14, 28, 32), 'flask.request.get_json', 'request.get_json', ({}, {}), '()', False, 'from flask import Flask, request\n'), ((35, 27, 35, 38), 'time.time', 'time.time', ({}, {}), '()', False, 'import time\n'), ((55, 11, 55, 58), 'json.dumps', 'json.dumps', ({(55, 22, 55, 57): 'blockchain.unconfirmed_transactions'}, {}), '(blockchain.unconfirmed_transactions)', False, 'import json\n'), ((79, 17, 79, 35), 'flask.request.get_json', 'request.get_json', ({}, {}), '()', False, 'from flask import Flask, request\n'), ((80, 12, 80, 120), 'block.Block', 'Block', ({(80, 18, 80, 37): "block_data['index']", (80, 39, 80, 65): "block_data['transactions']", (80, 67, 80, 119): "block_data['timestamp', block_data['previous_hash']]"}, {}), "(block_data['index'], block_data['transactions'], block_data[\n    'timestamp', block_data['previous_hash']])", False, 'from block import Block\n'), ((93, 32, 93, 74), 'json.dumps', 'json.dumps', (), '', False, 'import json\n')]