import os.path
import logging

from paramiko import AuthenticationException

from . import ceph
from . import fuel
from . import openstack
from ..utils import parse_creds, StopTestError
from ..test_run_class import TestRun
from ..node import Node


logger = logging.getLogger("wally.discover")


openrc_templ = """#!/bin/sh
export LC_ALL=C
export OS_NO_CACHE='true'
export OS_TENANT_NAME='{tenant}'
export OS_USERNAME='{name}'
export OS_PASSWORD='{passwd}'
export OS_AUTH_URL='{auth_url}'
export OS_INSECURE={insecure}
export OS_AUTH_STRATEGY='keystone'
export OS_REGION_NAME='RegionOne'
export CINDER_ENDPOINT_TYPE='publicURL'
export GLANCE_ENDPOINT_TYPE='publicURL'
export KEYSTONE_ENDPOINT_TYPE='publicURL'
export NOVA_ENDPOINT_TYPE='publicURL'
export NEUTRON_ENDPOINT_TYPE='publicURL'
"""


def discover(testrun: TestRun, discover_cfg, clusters_info, var_dir, discover_nodes=True):
    """Discover nodes in clusters"""
    nodes_to_run = []
    clean_data = None

    for cluster in discover_cfg:
        if cluster == "openstack" and not discover_nodes:
            logger.warning("Skip openstack cluster discovery")
        elif cluster == "openstack" and discover_nodes:
            cluster_info = clusters_info["openstack"]
            conn = cluster_info['connection']
            user, passwd, tenant = parse_creds(conn['creds'])

            auth_data = dict(
                auth_url=conn['auth_url'],
                username=user,
                api_key=passwd,
                project_id=tenant)

            if not conn:
                logger.error("No connection provided for %s. Skipping"
                             % cluster)
                continue

            logger.debug("Discovering openstack nodes "
                         "with connection details: %r" %
                         conn)

            os_nodes = openstack.discover_openstack_nodes(auth_data,
                                                          cluster_info)
            nodes_to_run.extend(os_nodes)

        elif cluster == "fuel" or cluster == "fuel_openrc_only":
            if cluster == "fuel_openrc_only":
                discover_nodes = False

            ssh_creds = clusters_info['fuel']['ssh_creds']
            fuel_node = Node(NodeInfo(ssh_creds, {'fuel_master'}))

            try:
                fuel_node.connect_ssh()
            except AuthenticationException:
                raise StopTestError("Wrong fuel credentials")
            except Exception:
                logger.exception("While connection to FUEL")
                raise StopTestError("Failed to connect to FUEL")

            fuel_node.connect_rpc()

            res = fuel.discover_fuel_nodes(fuel_node,
                                           clusters_info['fuel'],
                                           discover_nodes)
            nodes, clean_data, openrc_dict, version = res

            if openrc_dict:
                if version >= [8, 0] and openrc_dict['os_auth_url'].startswith("https://"):
                    logger.warning("Fixing FUEL 8.0 AUTH url - replace https://->http://")
                    openrc_dict['os_auth_url'] = "http" + openrc_dict['os_auth_url'][5:]

                testrun.fuel_openstack_creds = {
                    'name': openrc_dict['username'],
                    'passwd': openrc_dict['password'],
                    'tenant': openrc_dict['tenant_name'],
                    'auth_url': openrc_dict['os_auth_url'],
                    'insecure': openrc_dict['insecure']}

            env_name = clusters_info['fuel']['openstack_env']
            env_f_name = env_name
            for char in "-+ {}()[]":
                env_f_name = env_f_name.replace(char, '_')

            fuel_openrc_fname = os.path.join(var_dir,
                                             env_f_name + "_openrc")

            if testrun.fuel_openstack_creds is not None:
                with open(fuel_openrc_fname, "w") as fd:
                    fd.write(openrc_templ.format(**testrun.fuel_openstack_creds))
                msg = "Openrc for cluster {0} saves into {1}"
                logger.info(msg.format(env_name, fuel_openrc_fname))
            nodes_to_run.extend(nodes)

        elif cluster == "ceph":
            if discover_nodes:
                cluster_info = clusters_info["ceph"]
                nodes_to_run.extend(ceph.discover_ceph_nodes(cluster_info))
            else:
                logger.warning("Skip ceph cluster discovery")
        else:
            msg_templ = "Unknown cluster type in 'discover' parameter: {0!r}"
            raise ValueError(msg_templ.format(cluster))

    return nodes_to_run
