#!/usr/bin/env python
from __future__ import print_function, unicode_literals

import argparse
import codecs
import glob
import os
import platform
import shutil
import sys
import tempfile

from subprocess import check_call, check_output


_PY3 = sys.version_info.major == 3
_WINDOWS = platform.system().lower() == 'windows'
_PACKAGE_NAME = os.environ.get(
    'CLI_PACKAGE_NAME', 'github.com/urfave/cli'
)
_TARGETS = {}


def main(sysargs=sys.argv[:]):
    parser = argparse.ArgumentParser()
    parser.add_argument(
        'target', nargs='?', choices=tuple(_TARGETS.keys()), default='test'
    )
    args = parser.parse_args(sysargs[1:])

    _TARGETS[args.target]()
    return 0


def _target(func):
    _TARGETS[func.__name__.strip('_')] = func
    return func


@_target
def _test():
    if _go_version() < 'go1.2':
        _run('go test -v .')
        return

    coverprofiles = []
    for subpackage in ['', 'altsrc']:
        coverprofile = 'cli.coverprofile'
        if subpackage != '':
            coverprofile = '{}.coverprofile'.format(subpackage)

        coverprofiles.append(coverprofile)

        _run('go test -v'.split() + [
            '-coverprofile={}'.format(coverprofile),
            ('{}/{}'.format(_PACKAGE_NAME, subpackage)).rstrip('/')
        ])

    combined_name = _combine_coverprofiles(coverprofiles)
    _run('go tool cover -func={}'.format(combined_name))
    os.remove(combined_name)


@_target
def _gfmrun():
    go_version = _go_version()
    if go_version < 'go1.3':
        print('runtests: skip on {}'.format(go_version), file=sys.stderr)
        return
    _run(['gfmrun', '-c', str(_gfmrun_count()), '-s', 'README.md'])


@_target
def _vet():
    _run('go vet ./...')


@_target
def _migrations():
    go_version = _go_version()
    if go_version < 'go1.3':
        print('runtests: skip on {}'.format(go_version), file=sys.stderr)
        return

    migration_script = os.path.abspath(
        os.environ.get('V1TOV2', './cli-v1-to-v2')
    )
    v1_readme_url = os.environ.get(
        'V1README',
        'https://raw.githubusercontent.com/urfave/cli/v1/README.md'
    )

    tmpdir = tempfile.mkdtemp()
    try:
        os.chdir(tmpdir)
        _run('curl -sSL -o README.md {}'.format(v1_readme_url).split())
        _run('gfmrun extract -o .'.split())

        for gofile in glob.glob('*.go'):
            for i in (0, 1):
                _run(['python', migration_script, '-w', gofile])
                _run('go build -o tmp.out {}'.format(gofile).split())
    finally:
        if os.environ.get('NOCLEAN', '') == '':
            shutil.rmtree(tmpdir, ignore_errors=True)


@_target
def _toc():
    exe = ['bash'] if _WINDOWS else []
    _run(exe + [
        os.path.join('node_modules', '.bin', 'markdown-toc'),
        '-i', 'README.md'
    ])
    _run('git diff --exit-code')


@_target
def _gen():
    go_version = _go_version()
    if go_version < 'go1.5':
        print('runtests: skip on {}'.format(go_version), file=sys.stderr)
        return

    _run('go generate ./...')
    _run('git diff --exit-code')


def _run(command):
    if hasattr(command, 'split'):
        command = command.split()
    print('runtests: {}'.format(' '.join(command)), file=sys.stderr)
    sys.stderr.flush()
    check_call(command)


def _gfmrun_count():
    with codecs.open('README.md', 'r', 'utf-8') as infile:
        lines = infile.read().splitlines()
        return len(list(filter(_is_go_runnable, lines)))


def _is_go_runnable(line):
    return line.startswith('package main')


def _go_version():
    return check_output('go version'.split()).decode('utf-8').split()[2]


def _combine_coverprofiles(coverprofiles):
    tmp_args = dict(suffix='.coverprofile', mode='w', delete=False)
    if _PY3:
        tmp_args['encoding'] = 'utf-8'

    combined = tempfile.NamedTemporaryFile(**tmp_args)
    combined.write('mode: set\n')

    for coverprofile in coverprofiles:
        with codecs.open(coverprofile, 'r', 'utf-8') as infile:
            for line in infile.readlines():
                if not line.startswith('mode: '):
                    combined.write(line)

    combined.flush()
    name = combined.name
    combined.close()
    return name


if __name__ == '__main__':
    sys.exit(main())
