import asyncio
from tabulate import tabulate
from copy import deepcopy
import re
import os
import sys
import time

lock = asyncio.Lock()
logs_path = "/tmp/darkfi/"

node_info = {
}

ping_times = {
}

def debug(line):
    #print(line)
    pass

def process(info, line):
    regex_listen = re.compile(
        ".* Listening on (\d+[.]\d+[.]\d+[.]\d+:\d+)")
    regex_inbound_connect = re.compile(
        ".* Connected inbound \[(\d+[.]\d+[.]\d+[.]\d+:\d+)\]")
    regex_outbound_slots = re.compile(
        ".* Starting (\d+) outbound connection slots.")
    regex_outbound_connect = re.compile(
        ".* #(\d+) connected to outbound \[(\d+[.]\d+[.]\d+[.]\d+:\d+)\]")
    regex_channel_disconnected = re.compile(
        ".* Channel (\d+[.]\d+[.]\d+[.]\d+:\d+) disconnected")
    regex_pong_recv = re.compile(
        ".* Received Pong message (\d+)ms from \[(\d+[.]\d+[.]\d+[.]\d+:\d+)\]")

    if "net: P2p::start() [BEGIN]" in line:
        info["status"] = "p2p-start"
    elif "net: SeedSession::start() [START]" in line:
        info["status"] = "seed-start"
    elif "net: SeedSession::start() [END]" in line:
        info["status"] = "seed-done"
    elif "net: P2p::start() [END]" in line:
        info["status"] = "p2p-done"
    elif "net: P2p::run() [BEGIN]" in line:
        info["status"] = "p2p-run"
    elif "Not configured for accepting incoming connections." in line:
        info["inbounds"] = ["Disabled"]
    elif (match := regex_listen.match(line)) is not None:
        address = match.group(1)
        info["listen"] = address
    elif (match := regex_inbound_connect.match(line)) is not None:
        address = match.group(1)
        info["inbounds"].append(address)
    elif (match := regex_outbound_slots.match(line)) is not None:
        slots = match.group(1)
        info["outbounds"] = ["None" for _ in range(int(slots))]
    elif (match := regex_outbound_connect.match(line)) is not None:
        slot = match.group(1)
        address = match.group(2)
        info["outbounds"][int(slot)] = address
    elif (match := regex_channel_disconnected.match(line)) is not None:
        address = match.group(1)
        try:
            info["inbounds"].remove(address)
        except ValueError:
            pass
        try:
            idx = info["outbounds"].index(address)
            info["outbounds"][idx] = "None"
        except ValueError:
            pass
    elif (match := regex_pong_recv.match(line)) is not None:
        ping_time = match.group(1)
        address = match.group(2)
        ping_times[address] = ping_time

async def scanner(filename):
    global table_data

    async with lock:
        node_info[filename] = {
            "status": "none",
            "inbounds": [],
            "outbounds": [],
        }
        info = node_info[filename]

    with open(logs_path + filename) as fileh:
        while True:
            line = fileh.readline()
            if line:
                debug("R: " + filename + ": " + line[:-1])
                async with lock:
                    process(info, line)
            else:
                await asyncio.sleep(0.5)

def clear_lines(n):
    for i in range(n):
        sys.stdout.write('\033[F')

def get_ping(addr):
    ping_time = "none"
    if addr in ping_times:
        ping_time = str(ping_times[addr]) + " ms"
    return ping_time

def table_format(ninfo):
    table_data = []
    for filename, info in ninfo.items():
        table_data.append([filename, "", ""])
        table_data.append(["", "status", info["status"]])

        if "listen" in info:
            table_data.append(["", "listen", info["listen"]])

        inbounds = info["inbounds"]
        if inbounds:
            table_data.append(["", "inbounds", inbounds[0],
                               get_ping(inbounds[0])])

            for inbound in inbounds[1:]:
                table_data.append(["", "", inbound, get_ping(inbound)])

        outbounds = info["outbounds"]
        if outbounds:
            table_data.append(["", "outbounds", outbounds[0],
                               get_ping(outbounds[0])])

            for outbound in outbounds[1:]:
                table_data.append(["", "", outbound, get_ping(outbound)])

    headers = ["Name", "Attribute", "Value", "Ping Times"]
    return headers, table_data

async def refresh_table(tick=1):
    for filename in os.listdir(logs_path):
        asyncio.create_task(scanner(filename))

    previous_lines = 0

    while True:
        clear_lines(previous_lines)

        async with lock:
            ninfo = deepcopy(node_info)
        headers, table_data = table_format(ninfo)
        lines = tabulate(table_data, headers=headers).split("\n")
        debug("-------------------")
        for line in lines:
            print('\x1b[2K\r', end="")
            print(line)

        previous_lines = len(lines)

        await asyncio.sleep(1)

asyncio.run(refresh_table())

