import sys
from datetime import datetime, timedelta
from prettytable import PrettyTable
import argparse
from timeit import default_timer as timer
import logging
from beem.blockchain import Blockchain
from beem.block import Block
from beem import Hive, Blurt, Steem
from beem.utils import parse_time
from beem.nodelist import NodeList

log = logging.getLogger(__name__)
logging.basicConfig(level=logging.INFO)


def parse_args(args=None):
    d = 'Show op type stats for either hive, blurt or steem.'
    parser = argparse.ArgumentParser(description=d)
    parser.add_argument('blockchain', type=str, nargs='?',
                        default=sys.stdin,
                        help='Blockchain (hive, blurt or steem)')
    return parser.parse_args(args)


def main(args=None):
    
    args = parse_args(args)
    blockchain = args.blockchain
    
    nodelist = NodeList()
    nodelist.update_nodes(weights={"block": 1})
    
    if blockchain == "hive" or blockchain is None:
        max_batch_size = 50
        threading = False
        thread_num = 16
        block_debug = 1000
        
        nodes = nodelist.get_hive_nodes()
        blk_inst = Hive(node=nodes, num_retries=3, num_retries_call=3, timeout=30)
    elif blockchain == "blurt":
        max_batch_size = None
        threading = False
        thread_num = 8
        block_debug = 20
        nodes = ["https://rpc.blurt.buzz/", "https://api.blurt.blog", "https://rpc.blurtworld.com", "https://rpc.blurtworld.com"]
        blk_inst = Blurt(node=nodes, num_retries=3, num_retries_call=3, timeout=30)
    elif blockchain == "steem":
        max_batch_size = 50
        threading = False
        thread_num = 16
        block_debug = 1000
        nodes = nodelist.get_steem_nodes()
        blk_inst = Steem(node=nodes, num_retries=3, num_retries_call=3, timeout=30)
    else:
        raise Exception("Wrong parameter, can be hive, blurt or steem")
    print(blk_inst)
    block_count = 0
    total_ops = 0
    total_trx = 0
    duration_s = 60 * 60 * 1
    blocksperday = int(duration_s / 3)
    
    blockchain = Blockchain(blockchain_instance=blk_inst, )
    current_block_num = blockchain.get_current_block_num()
    last_block_id = current_block_num - blocksperday

    last_block = Block(last_block_id, blockchain_instance=blk_inst)

    stopTime = last_block.time() + timedelta(seconds=duration_s)

    start = timer()
    op_stats = {}
    for entry in blockchain.blocks(start=last_block_id, max_batch_size=max_batch_size, threading=threading, thread_num=thread_num):
        if "block" in entry:
            block_time = parse_time(entry["block"]["timestamp"])
        else:
            block_time = entry["timestamp"]
        if block_time > stopTime:
            break
        block_count += 1
        if "block" in entry:
            trxs = entry["block"]["transactions"]
        else:
            trxs = entry["transactions"]
        for tx in trxs:
            total_trx += 1
            for op in tx["operations"]:
                if "_operation" in op["type"]:
                    op_type = op["type"][:-10]
                else:
                    op_type = op["type"]
                if op_type in op_stats:
                    op_stats[op_type] += 1
                else:
                    op_stats[op_type] = 1
                total_ops += 1

        ops_per_day = total_ops / block_count * blocksperday
        if block_count % (block_debug) == 0:
            print("%d blocks remaining... estimated ops per day: %.1f" % (blocksperday - block_count, ops_per_day))

    duration = timer() - start    
    t = PrettyTable(["Type", "Count", "percentage"])
    t.align = "l"
    op_list = []
    for o in op_stats:
        op_list.append({"type": o, "n": op_stats[o], "perc": op_stats[o] / total_ops * 100})
    op_list_sorted = sorted(op_list, key=lambda x: x['n'], reverse=True)
    for op in op_list_sorted:
        t.add_row([op["type"], op["n"], "%.2f %%" % op["perc"]])
    print(t)
if __name__ == '__main__':
    sys.exit(main())