from requests import get, exceptions
from bs4 import BeautifulSoup
from datetime import datetime
from termcolor import colored
from yaml import safe_dump
from random import uniform
from time import sleep, time
from statistics import median


def save_data(data, file_path, open_mode, timestamp=False):
    try:
        if timestamp:
            datestamp = datetime.today().strftime('%d-%m-%Y_%H-%M')
            if "." in file_path:
                file_path_parts = file_path.split(".")
                file_path = file_path_parts[0] + f"_{datestamp}." + file_path_parts[1]
            else:
                file_path = file_path + f"_{datestamp}"

        with open(file_path, open_mode) as data_file:
            data_file.write(safe_dump(data))

    except FileNotFoundError as file_not_found_err:
        print(f"Execution of {save_data.__name__} has ended with following error:\n{file_not_found_err}")
        print("File you have specified was not found! You can try one of the following:")
        print("Check the specified file path.\nCheck the file permissions.\nCheck file opening mode.")

    except FileExistsError as file_exists_err:
        print(f"Execution of {save_data.__name__} has ended with following error:\n{file_exists_err}")
        print("File you have specified already exists! You can try one of the following:")
        print("Check the specified file path.\nCheck file opening mode.")
        overwrite = input("\nDo you wish to overwrite the file (y/n)?")
        if overwrite == "Y" or overwrite == "y":
            save_data(data, file_path, "w", timestamp=False)

    return None


def get_html(url, retry_limit):
    html = ""
    retries = 0
    while True:
        try:
            html = get(url).text
            break

        except exceptions.InvalidURL:
            print("Invalid URL given!")
            break

        except exceptions.Timeout:
            if retries == retry_limit:
                print("GET request failed. Retry limit reached!")
                break
            print("Connection timeout. Retrying ...")
            retries += 1
            sleep(0.5)
            continue

        except exceptions.ConnectionError:
            if retries == retry_limit:
                print("GET request failed. No connection!")
                break
            print("No connection. Retrying ...")
            retries += 1
            sleep(0.5)
            continue

        except exceptions.RequestException:
            print("GET request failed.")
            break

    return html


def gather_cpu_data(benchmark_url):
    data_parser = BeautifulSoup(get(benchmark_url).text, "html.parser")
    data = {"hash_rates": [float(bench.find_all("td")[1].text) for bench in data_parser.find("tbody").find_all("tr")]}
    data["valid_samples"] = len(data["hash_rates"])
    data["min_hash"] = data["hash_rates"][-1]
    data["avg_hash"] = round(sum(data["hash_rates"]) / len(data["hash_rates"]), 2)
    data["median"] = round(median(data["hash_rates"]), 2)
    data["max_hash"] = data["hash_rates"][0]
    return data


if __name__ == '__main__':
    start = time()
    cpu_dict = {}
    cpu_list_parser = BeautifulSoup(get("https://xmrig.com/benchmark").text, "html.parser")
    for cpu in cpu_list_parser.find("tbody").find_all("tr"):
        name = cpu.find("span").text.replace(" ", "_")
        cpu_dict[name] = gather_cpu_data("https://xmrig.com" + cpu.find("a")["href"])
        print(f"{colored('OK', color='green')} - Got {cpu_dict[name]['valid_samples']} valid benchmarks for {name}.")
        sleep(round(uniform(0.5, 1.0), 2))

    save_data(cpu_dict, "data/xmrig_benchmarks.yaml", "w", timestamp=True)
    print(f"{colored('DONE', color='green')} - time elapsed: {round(time() - start, 2)} sec.")
