"""
Module responsible for running the Ansible part of the OpenAppStack setup.
"""
import logging
import os
import subprocess
import yaml

log = logging.getLogger(__name__)  # pylint: disable=invalid-name

ANSIBLE_INVENTORY = './clusters/{cluster_name}/inventory.yml'
ANSIBLE_PATH = os.path.join(os.path.dirname(__file__),
                            '..', 'ansible')

def run_ansible(clus, playbook, ansible_params=None):
    """
    Call `ansible-playbook` in a subprocess to run the specified playbook. Runs
    in the package's ansible directory.

    :param str playbook: path to the playbook to run.
    :param list ansible_params: Optionally provide a list of lists with ansible
        params.  Each inner list may only contain one element. Can be directly
        forwarded from argparse. Example:
        `ansible_params = [[become-user=root], [verbose]]`
    """
    # playbook path here is relative to private_data_dir/project, see
    # https://ansible-runner.readthedocs.io/en/latest/intro.html#inputdir
    ansible_playbook_command = ['ansible-playbook']
    if ansible_params:
        for param in ansible_params:
            if len(param) > 1:
                log.warning('More than 1 parameter. Ignoring the rest! Use '
                            '--ansible-param several times to supply '
                            'more than 1 parameter')
            param = param[0]
            ansible_playbook_command.append(param)
    ansible_playbook_command += \
        ['-e', 'cluster_dir=' + clus.cluster_dir]

    ansible_playbook_command += \
        ['-i', clus.inventory_file, playbook]

    log.info('Running "%s" in ansible directory "%s"',
             ansible_playbook_command,
             ANSIBLE_PATH)

    process = subprocess.Popen(
        ansible_playbook_command,
        cwd=ANSIBLE_PATH)

    returncode = process.wait()

    if returncode > 0:
        raise RuntimeError('Playbook failed with rc %s.'
                           % returncode)

def create_inventory(cluster):
    """
    Creates inventory for the ansible playbook. Needs the droplet's hostname
    for identification and the IP for connecting with Ansible

    :param cluster.Cluster cluster: Cluster object to for which inventory file
        will be written. Used for getting hostname and IP address.
    """
    # Create inventory
    with open(os.path.join(ANSIBLE_PATH, 'inventory.yml.example'),
              'r') as stream:
        inventory = yaml.safe_load(stream)

    # Rename the hostname in the inventory to one provided by the user.
    if cluster.hostname != 'oas-dev':
        inventory['all']['hosts'][cluster.hostname] = \
            inventory['all']['hosts']['oas-dev']
        del inventory['all']['hosts']['oas-dev']

    inventory['all']['hosts'][cluster.hostname]['ansible_host'] = \
        cluster.ip_address
    inventory['all']['hosts'][cluster.hostname]['domain'] = \
        cluster.domain

    if cluster.docker_mirror_endpoint \
            and cluster.docker_mirror_server \
            and cluster.docker_mirror_username \
            and cluster.docker_mirror_password:
        docker_mirror = {}
        docker_mirror['enabled'] = True
        docker_mirror['endpoint'] = cluster.docker_mirror_endpoint
        docker_mirror['username'] = cluster.docker_mirror_username
        docker_mirror['password'] = cluster.docker_mirror_password
        docker_mirror['server'] = cluster.docker_mirror_server
        inventory['all']['hosts'][cluster.hostname]['docker_mirror'] = \
            docker_mirror

    inventory['all']['children']['master']['hosts'] = cluster.hostname
    inventory['all']['children']['worker']['hosts'] = cluster.hostname

    file_contents = yaml.safe_dump(inventory, default_flow_style=False)
    log.debug(file_contents)
    with open(cluster.inventory_file, 'w') as stream:
        stream.write(file_contents)
        log.info("Created %s", cluster.inventory_file)
    return inventory