#
# coding=utf-8
# flake8: noqa E302
"""Development related tasks to be run with 'invoke'.

Make sure you satisfy the following Python module requirements if you are trying to publish a release to PyPI:
    - twine >= 1.11.0
    - wheel >= 0.31.0
    - setuptools >= 39.1.0
"""
import os
import pathlib
import shutil

import invoke

TASK_ROOT = pathlib.Path(__file__).resolve().parent
TASK_ROOT_STR = str(TASK_ROOT)

# shared function
def rmrf(items, verbose=True):
    """Silently remove a list of directories or files"""
    if isinstance(items, str):
        items = [items]

    for item in items:
        if verbose:
            print("Removing {}".format(item))
        shutil.rmtree(item, ignore_errors=True)
        # rmtree doesn't remove bare files
        try:
            os.remove(item)
        except FileNotFoundError:
            pass


# create namespaces
namespace = invoke.Collection()
namespace_clean = invoke.Collection('clean')
namespace.add_collection(namespace_clean, 'clean')

#####
#
# pytest, pylint, and codecov
#
#####


@invoke.task
def pytest(context, junit=False, pty=True, append_cov=False):
    """Run tests and code coverage using pytest"""
    ROOT_PATH = TASK_ROOT.parent.parent

    with context.cd(str(ROOT_PATH)):
        command_str = 'pytest --cov=cmd2_ext_test --cov-report=term --cov-report=html'
        if append_cov:
            command_str += ' --cov-append'
        if junit:
            command_str += ' --junitxml=junit/test-results.xml'
        command_str += ' ' + str((TASK_ROOT / 'tests').relative_to(ROOT_PATH))
        context.run(command_str, pty=pty)


namespace.add_task(pytest)


@invoke.task
def pytest_clean(context):
    """Remove pytest cache and code coverage files and directories"""
    # pylint: disable=unused-argument
    with context.cd(TASK_ROOT_STR):
        dirs = ['.pytest_cache', '.cache', 'htmlcov', '.coverage']
        rmrf(dirs)


namespace_clean.add_task(pytest_clean, 'pytest')


@invoke.task
def mypy(context):
    """Run mypy optional static type checker"""
    with context.cd(TASK_ROOT_STR):
        context.run("mypy cmd2_ext_test")
        namespace.add_task(mypy)


namespace.add_task(mypy)


@invoke.task
def mypy_clean(context):
    """Remove mypy cache directory"""
    # pylint: disable=unused-argument
    with context.cd(TASK_ROOT_STR):
        dirs = ['.mypy_cache', 'dmypy.json', 'dmypy.sock']
        rmrf(dirs)


namespace_clean.add_task(mypy_clean, 'mypy')


#####
#
# documentation
#
#####


#####
#
# build and distribute
#
#####
BUILDDIR = 'build'
DISTDIR = 'dist'


@invoke.task
def build_clean(context):
    """Remove the build directory"""
    # pylint: disable=unused-argument
    with context.cd(TASK_ROOT_STR):
        rmrf(BUILDDIR)


namespace_clean.add_task(build_clean, 'build')


@invoke.task
def dist_clean(context):
    """Remove the dist directory"""
    # pylint: disable=unused-argument
    with context.cd(TASK_ROOT_STR):
        rmrf(DISTDIR)


namespace_clean.add_task(dist_clean, 'dist')


#
# make a dummy clean task which runs all the tasks in the clean namespace
clean_tasks = list(namespace_clean.tasks.values())


@invoke.task(pre=list(namespace_clean.tasks.values()), default=True)
def clean_all(context):
    """Run all clean tasks"""
    # pylint: disable=unused-argument
    pass


namespace_clean.add_task(clean_all, 'all')


@invoke.task(pre=[clean_all])
def sdist(context):
    """Create a source distribution"""
    with context.cd(TASK_ROOT_STR):
        context.run('python setup.py sdist')


namespace.add_task(sdist)


@invoke.task(pre=[clean_all])
def wheel(context):
    """Build a wheel distribution"""
    with context.cd(TASK_ROOT_STR):
        context.run('python setup.py bdist_wheel')


namespace.add_task(wheel)


@invoke.task(pre=[sdist, wheel])
def pypi(context):
    """Build and upload a distribution to pypi"""
    with context.cd(TASK_ROOT_STR):
        context.run('twine upload dist/*')


namespace.add_task(pypi)


@invoke.task(pre=[sdist, wheel])
def pypi_test(context):
    """Build and upload a distribution to https://test.pypi.org"""
    with context.cd(TASK_ROOT_STR):
        context.run('twine upload --repository-url https://test.pypi.org/legacy/ dist/*')


namespace.add_task(pypi_test)


# Flake8 - linter and tool for style guide enforcement and linting
@invoke.task
def flake8(context):
    """Run flake8 linter and tool for style guide enforcement"""
    with context.cd(TASK_ROOT_STR):
        context.run(
            "flake8 --ignore=E252,W503 --max-complexity=26 --max-line-length=127 --show-source --statistics "
            "--exclude=.git,__pycache__,.tox,.nox,.eggs,*.egg,.venv,.idea,.pytest_cache,.vscode,build,dist,htmlcov"
        )


namespace.add_task(flake8)
