import time
import json
import os.path
import logging

from concurrent.futures import ThreadPoolExecutor, wait

from disk_perf_test_tool.ssh_utils import connect, copy_paths

logger = logging.getLogger('io-perf-tool')


def wait_all_ok(futures):
    return all(future.result() for future in futures)


def deploy_and_start_sensors(monitor_uri, config,
                             remote_path='/tmp/sensors',
                             connected_config=None):

    paths = {os.path.dirname(__file__): remote_path}
    with ThreadPoolExecutor(max_workers=32) as executor:
        futures = []

        if connected_config is not None:
            assert config is None
            node_iter = connected_config
        else:
            node_iter = config.items()

        for uri_or_conn, config in node_iter:
            futures.append(executor.submit(deploy_and_start_sensor,
                                           paths, uri_or_conn,
                                           monitor_uri,
                                           config, remote_path))

        if not wait_all_ok(futures):
            raise RuntimeError("Sensor deployment fails on some nodes")


def deploy_and_start_sensor(paths, uri_or_conn, monitor_uri, config,
                            remote_path):
    try:
        if isinstance(uri_or_conn, basestring):
            conn = connect(uri_or_conn)
        else:
            conn = uri_or_conn

        copy_paths(conn, paths)
        sftp = conn.open_sftp()

        config_remote_path = os.path.join(remote_path, "conf.json")
        main_remote_path = os.path.join(remote_path, "main.py")

        with sftp.open(config_remote_path, "w") as fd:
            fd.write(json.dumps(config))

        cmd_templ = "python {0} -d start -u {1} {2}"
        cmd = cmd_templ.format(main_remote_path,
                               monitor_uri,
                               config_remote_path)
        conn.exec_command(cmd)
        sftp.close()

        if isinstance(uri_or_conn, basestring):
            conn.close()
    except:
        logger.exception("During deploing sensors in {0}".format(uri_or_conn))
        return False
    return True


def stop_and_remove_sensor(uri_or_conn, remote_path):
    if isinstance(uri_or_conn, basestring):
        conn = connect(uri_or_conn)
    else:
        conn = uri_or_conn

    main_remote_path = os.path.join(remote_path, "main.py")

    cmd_templ = "python {0} -d stop"
    conn.exec_command(cmd_templ.format(main_remote_path))

    # some magic
    time.sleep(0.3)

    conn.exec_command("rm -rf {0}".format(remote_path))

    if isinstance(uri_or_conn, basestring):
        conn.close()

    logger.debug("Sensors stopped and removed")


def stop_and_remove_sensors(config, remote_path='/tmp/sensors',
                            connected_config=None):
    with ThreadPoolExecutor(max_workers=32) as executor:
        futures = []

        if connected_config is not None:
            assert config is None
            conf_iter = connected_config
        else:
            conf_iter = config.items()

        for uri_or_conn, config in conf_iter:
            futures.append(executor.submit(stop_and_remove_sensor,
                                           uri_or_conn, remote_path))

        wait(futures)
