#!/usr/bin/env python
"""
lpmptox script will run tox on changes in a selected MP

lpmptox depends on ``launchpadlib``, which isn't
necessarily up-to-date in PyPI, so we install it from the archive::

`sudo apt-get install python-launchpadlib` OR

`sudo apt-get install python3-launchpadlib` OR

As we're using ``launchpadlib`` from the archive (which is therefore
installed in the system), you'll need to create your virtualenvs
with the ``--system-site-packages`` option.

Activate your virtualenv and install the requirements::

`pip install -r requirements.txt`


"""
import click
import git
import os
import subprocess
from tempfile import TemporaryDirectory
import urwid

from lpshipit import (
    _get_launchpad_client,
    _set_urwid_widget,
    summarize_git_mps,
)
from lxc import lxc_container

# Global var to store the chosen MP
CHOSEN_MP = None

def _write_debug(output_file, message):
    output_file.write('{}\n'.format(message))
    output_file.flush()
    print(message)


def runtox(source_repo, source_branch,
           tox_command='tox --recreate --parallel auto',
           output_filepath=os.devnull,
           environment=None):
    with open(output_filepath, "a") as output_file, TemporaryDirectory() as local_repo:
        _write_debug(output_file, 'Cloning {} (branch {}) in to tmp directory {} ...'.format(
            source_repo,
            source_branch,
            local_repo))
        repo = git.Repo.clone_from(
            source_repo,
            local_repo,
            depth=1,
            single_branch=True,
            branch=source_branch
        )
        _write_debug(output_file, '{} {}'.format(
            repo.head.object.hexsha,
            repo.head.object.summary
        ))

        if environment is not None:
            _write_debug(output_file,
                         'Running `{}` in {} lxc environment ...'.format(
                             tox_command, environment))
            return _run_tox_in_lxc(environment, local_repo, tox_command,
                                   output_file)
        else:
            _write_debug(output_file,
                         'Running `{}` in {} ...'.format(tox_command,
                                                         local_repo))
            return _run_tox_locally(local_repo, tox_command, output_file)


def _run_tox_in_lxc(environment, local_repo, tox_command, output_file):
    with lxc_container(environment, local_repo) as container:
        # If a proxy has been configured on the host using environment
        # variables http_proxy or https_proxy then the container will inherit
        # this proxy config for the default user. However then calling sudo
        # this proxy config is no longer configured. To fix this and so sudo
        # calls use the same proxy we can use `--preserve-env`
        # http://manpages.ubuntu.com/manpages/focal/man8/sudo.8.html to pass
        # in a list of environment variables we want set for sudo user too.
        sudo_preserve_proxy = '--preserve-env="http_proxy,https_proxy"'
        container.run_command('sudo {} apt-get update'.format(sudo_preserve_proxy))
        container.run_command('sudo {} apt-get install -y python3-pip'.format(sudo_preserve_proxy))
        container.run_command('sudo {} pip3 install tox'.format(sudo_preserve_proxy))
        # local_repo is same path in the container
        tox_returncode, tox_output = container.run_command(
            tox_command + ' -c ' + local_repo)
        _write_debug(output_file, tox_output)
        return tox_returncode


def _run_tox_locally(local_repo, tox_command, output_file):
    process = subprocess.Popen(tox_command,
                            stdout=subprocess.PIPE,
                            shell=True,
                            cwd=local_repo)
    while process.poll() is None:
        _write_debug(output_file, process.stdout.readline().decode('utf-8').rstrip())
    return process.returncode


@click.command()
@click.option('--mp-owner', help='LP username of the owner of the MP '
                                 '(Defaults to system configured user)',
              default=None)
@click.option('--source-repo', help='Repository to test', default=None)
@click.option('--source-branch', help='Branch to test', default=None)
@click.option('--debug/--no-debug', default=False)
@click.option('--environment', default=None, help='release (16.04, 18.04, etc) to run tox in')
def lpmptox(mp_owner, source_repo, source_branch, debug, environment):
    """Invokes the commit building with proper user inputs."""
    if not source_repo and not source_branch:
        lp = _get_launchpad_client()
        lp_user = lp.me

        print('Retrieving Merge Proposals from Launchpad...')
        person = lp.people[lp_user.name if mp_owner is None else mp_owner]
        mps = person.getMergeProposals(status=['Needs review', 'Approved'])
        if debug:
            print('Debug: Launchad returned {} merge proposals'.format(len(mps)))
        mp_summaries = summarize_git_mps(mps)

        if mp_summaries:

            def urwid_exit_on_q(key):
                if key in ('q', 'Q'):
                    raise urwid.ExitMainLoop()

            def mp_chosen(button, chosen_mp):
                global CHOSEN_MP
                CHOSEN_MP = chosen_mp

                raise urwid.ExitMainLoop()

            listwalker = urwid.SimpleFocusListWalker(list())
            listwalker.append(urwid.Text(u'Merge Proposal to Merge'))
            listwalker.append(urwid.Divider())

            for mp in mp_summaries:
                button = urwid.Button(mp['summary'])
                urwid.connect_signal(button, 'click', mp_chosen, mp)
                listwalker.append(button)
            mp_box = urwid.ListBox(listwalker)
            try:
                _set_urwid_widget(mp_box, urwid_exit_on_q)
            finally:
                if CHOSEN_MP:
                    source_repo = CHOSEN_MP['source_repo']
                    source_branch = CHOSEN_MP['source_branch']

        else:
            print("You have no Merge Proposals in either "
                  "'Needs review' or 'Approved' state")
    runtox(source_repo, source_branch, environment=environment)


if __name__ == "__main__":
    lpmptox()
