#!/usr/bin/env python
""" nf-core: Helper tools for use with nf-core Nextflow pipelines. """

from __future__ import print_function

import click
import sys
import os
import re

import nf_core
import nf_core.lint, nf_core.list, nf_core.download, nf_core.licences, nf_core.bump_version, nf_core.create

import logging

@click.group()
@click.version_option(nf_core.__version__)
@click.option(
    '-v', '--verbose',
    is_flag = True,
    help = "Verbose output (print debug statements)"
)
def nf_core_cli(verbose):
    if verbose:
        logging.basicConfig(level=logging.DEBUG, format="\n%(levelname)s: %(message)s")
    else:
        logging.basicConfig(level=logging.INFO, format="\n%(levelname)s: %(message)s")

@nf_core_cli.command()
@click.argument(
    'pipeline_dir',
    type = click.Path(exists=True),
    required = True,
    metavar = "<pipeline directory>"
)
@click.option(
    '--release',
    is_flag = True,
    default = os.environ.get('TRAVIS_BRANCH') == 'master' and os.environ.get('TRAVIS_REPO_SLUG', '').startswith('nf-core/') and not os.environ.get('TRAVIS_REPO_SLUG', '') == 'nf-core/tools',
    help = "Execute additional checks for release-ready workflows."
)
def lint(pipeline_dir, release):
    """ Check pipeline against nf-core guidelines """

    # Run the lint tests!
    lint_obj = nf_core.lint.run_linting(pipeline_dir, release)
    if len(lint_obj.failed) > 0:
        sys.exit(1)

@nf_core_cli.command()
@click.argument(
    'keywords',
    required = False,
    nargs = -1,
    metavar = "<filter keywords>"
)
@click.option(
    '-s', '--sort',
    type = click.Choice(['release', 'name', 'stars']),
    default = 'release',
    help = "How to sort listed pipelines"
)
@click.option(
    '--json',
    is_flag = True,
    default = False,
    help = "Print full output as JSON"
)
def list(sort, json, keywords):
    """ List nf-core pipelines with local info """
    nf_core.list.list_workflows(sort, json, keywords)

@nf_core_cli.command()
@click.argument(
    'pipeline',
    required = True,
    metavar = "<pipeline name>"
)
@click.option(
    '--json',
    is_flag = True,
    default = False,
    help = "Print output as JSON"
)
def licences(pipeline, json):
    """ List software licences for a given workflow """
    lic = nf_core.licences.WorkflowLicences(pipeline, json)
    lic.fetch_conda_licences()
    lic.print_licences()

@nf_core_cli.command()
@click.argument(
    'pipeline',
    required = True,
    metavar = "<pipeline name>"
)
@click.option(
    '-r', '--release',
    type = str,
    help = "Pipeline release"
)
@click.option(
    '-s', '--singularity',
    is_flag = True,
    default = False,
    help = "Download singularity containers"
)
@click.option(
    '-o', '--outdir',
    type = str,
    help = "Output directory"
)
def download(pipeline, release, singularity, outdir):
    """ Download a pipeline and singularity container """
    dl = nf_core.download.DownloadWorkflow(pipeline, release, singularity, outdir)
    dl.download_workflow()

@nf_core_cli.command('bump-version')
@click.argument(
    'pipeline_dir',
    type = click.Path(exists=True),
    required = True,
    metavar = "<pipeline directory>"
)
@click.argument(
    'new_version',
    required = True,
    metavar = "<new version>"
)
@click.option(
    '-n', '--nextflow',
    is_flag = True,
    default = False,
    help = "Bump required nextflow version instead of pipeline version"
)
def bump_version(pipeline_dir, new_version, nextflow):
    """ Update nf-core pipeline version number """

    # First, lint the pipeline to check everything is in order
    logging.info("Running nf-core lint tests")
    lint_obj = nf_core.lint.run_linting(pipeline_dir, False)

    # Bump the pipeline version number
    if not nextflow:
        nf_core.bump_version.bump_pipeline_version(lint_obj, new_version)
    else:
        nf_core.bump_version.bump_nextflow_version(lint_obj, new_version)

def validate_wf_name_prompt(ctx, opts, value):
    """ Force the workflow name to meet the nf-core requirements """
    if not re.match(r'^[a-z]+$', value):
        click.echo('Invalid workflow name: must be lowercase without punctuation.')
        value = click.prompt(opts.prompt)
        return validate_wf_name_prompt(ctx, opts, value)
    return value

@nf_core_cli.command()
@click.option(
    '-n', '--name',
    prompt = 'Workflow Name',
    required = True,
    callback = validate_wf_name_prompt,
    type = str,
    help = 'The name of your new pipeline'
)
@click.option(
    '-d', '--description',
    prompt = True,
    required = True,
    type = str,
    help = 'A short description of your pipeline'
)
@click.option(
    '-a', '--author',
    prompt = True,
    required = True,
    type = str,
    help = 'Name of the main author(s)'
)
@click.option(
    '--new-version',
    type = str,
    default = '1.0dev',
    help = 'The initial version number to use'
)
@click.option(
    '--no-git',
    is_flag = True,
    default = False,
    help = "Do not initialise pipeline as new git repository"
)
@click.option(
    '-f', '--force',
    is_flag = True,
    default = False,
    help = "Overwrite output directory if it already exists"
)
@click.option(
    '-o', '--outdir',
    type = str,
    help = "Output directory for new pipeline (default: pipeline name)"
)
def create(name, description, author, new_version, no_git, force, outdir):
    """ Create a new pipeline using the template """
    create_obj = nf_core.create.PipelineCreate(name, description, author, new_version, no_git, force, outdir)
    create_obj.init_pipeline()


if __name__ == '__main__':
    print("""
                                          ,--./,-.
          ___     __   __   __   ___     /,-._.--~\\
    |\ | |__  __ /  ` /  \ |__) |__         }  {
    | \| |       \__, \__/ |  \ |___     \`-._,-`-,
                                          `._,._,'
    """, file=sys.stderr)
    nf_core_cli()
