import argparse

import argcomplete
from argcomplete.completers import ChoicesCompleter

from retriever.engines import engine_list
from retriever.lib.defaults import VERSION, RETRIEVER_REPOSITORY
from retriever.lib.scripts import SCRIPT_LIST, get_dataset_names_upstream
from retriever.lib.rdatasets import get_rdataset_names

module_list = SCRIPT_LIST()
script_list = []
keywords_list = []
licenses_list = []

for module in module_list:
    script_list.append(module.name)

    if hasattr(module, "keywords"):
        # Add list of keywords to keywords_list
        if module.keywords:
            keywords_list += module.keywords

    if hasattr(module, "licenses"):
        # Append string to list of licenses_list
        if module.licenses:
            for dict_items in module.licenses:
                if dict_items['name']:
                    licenses_list.append(dict_items['name'])

script_list.extend(get_dataset_names_upstream(repo=RETRIEVER_REPOSITORY))
script_list.extend(get_dataset_names_upstream())
script_list.extend(get_rdataset_names())
script_list = sorted(set(script_list))

# set of all possible licenses, keywords and scripts
licenses_options = set(licenses_list)
keywords_options = set(keywords_list)
scripts_options = script_list

parser = argparse.ArgumentParser(prog="retriever")
parser.add_argument('-v', '--version', action='version', version=VERSION)
parser.add_argument('-q',
                    '--quiet',
                    help='suppress command-line output',
                    action='store_true')

# ..............................................................
# subparsers
# ..............................................................

# retriever HELP
subparsers = parser.add_subparsers(help='sub-command help', dest='command')

# retriever download/install/update/new help
download_parser = subparsers.add_parser('download',
                                        help='download raw data files for a dataset')
install_parser = subparsers.add_parser('install', help='download and install dataset')
default_parser = subparsers.add_parser('defaults', help='displays default options')
update_parser = subparsers.add_parser('update',
                                      help='download updated versions of scripts')
new_parser = subparsers.add_parser('new', help='create a new sample retriever script')
autocreate_parser = subparsers.add_parser(
    'autocreate', help='CLI to automatically create retriever scripts')
ls_parser = subparsers.add_parser('ls',
                                  help='display a list all available dataset scripts')
citation_parser = subparsers.add_parser('citation', help='view citation')
license_parser = subparsers.add_parser('license', help='view dataset license')
reset_parser = subparsers.add_parser(
    'reset',
    help='reset retriever: removes configuration settings, scripts, and cached data')
help_parser = subparsers.add_parser('help', help='')
commit_parser = subparsers.add_parser('commit', help='commit a dataset')
commit_log_parser = subparsers.add_parser('log', help='see log of a committed dataset')

# ..............................................................
# subparsers with Arguments
# ..............................................................

citation_parser.add_argument('dataset',
                             help='dataset name',
                             nargs='?',
                             default=None,
                             choices=script_list + [None])
commit_parser.add_argument('dataset', help='dataset name', choices=script_list)
commit_parser.add_argument('-p',
                           '--path',
                           help='path to store committed file',
                           default=None,
                           required=False)
commit_parser.add_argument('-m',
                           '--message',
                           help='commit message',
                           default=None,
                           required=True,
                           type=str)
commit_log_parser.add_argument('dataset', help='dataset name', choices=script_list)
license_parser.add_argument('dataset',
                            help='dataset name',
                            nargs='?',
                            default=None,
                            choices=script_list + [None])
new_parser.add_argument('filename', help='new script filename')
reset_parser.add_argument('scope', help='things to reset: all, scripts or data').completer = \
    ChoicesCompleter(script_list + ['all', 'scripts', 'data'])
install_parser.add_argument('--compile',
                            help='force re-compile of script before downloading',
                            action='store_true')
install_parser.add_argument('--debug', help='run in debug mode', action='store_true')
install_parser.add_argument('--not-cached',
                            help='overwrites local cache of raw data',
                            action='store_true')
download_parser.add_argument('--debug', help='run in debug mode', action='store_true')
download_parser.add_argument('--not-cached',
                             help='overwrites local cache of raw data',
                             action='store_true')
download_parser.add_argument('-b',
                             '--bbox',
                             nargs=4,
                             help='Set bounding box xmin, ymax, xmax, ymin',
                             required=False)

ls_parser.add_argument('-l', help='search datasets with specific license(s)',
                       nargs='+').completer = ChoicesCompleter(list(licenses_options))
ls_parser.add_argument('-k', help='search datasets with keyword(s)',
                       nargs='+').completer = ChoicesCompleter(list(keywords_options))
ls_parser.add_argument('-v', help='verbose list of specified dataset(s)',
                       nargs='+').completer = ChoicesCompleter(list(scripts_options))
ls_parser.add_argument('-s', help='search socrata datasets with name(s)', nargs='+')

rdataset_ls_subparser = ls_parser.add_subparsers(help='ls rdatasets help',
                                                 dest='rdataset')
rdataset_parser = rdataset_ls_subparser.add_parser(
    'rdataset',
    help='Display a list of all available rdatasets',
)
rdataset_parser.add_argument(
    '-p', help='display a list of all rdatasets present in the package(s)', nargs='+')

rdataset_parser.add_argument('all',
                             help='display all the packages present in rdatasets',
                             nargs='?',
                             default=None)

autocreate_parser.add_argument('path', help='path to the data file(s)')
autocreate_parser.add_argument('-dt',
                               help='datatype for files',
                               nargs='?',
                               default='tabular',
                               choices=['raster', 'vector', 'tabular'])
autocreate_parser.add_argument('-d',
                               help='turn a directory and subdirectories into scripts',
                               action='store_true')
autocreate_parser.add_argument('-e',
                               help='encoding of the source file',
                               nargs='?',
                               default='utf-8')
autocreate_parser.add_argument('-f', help='turn files into scripts', action='store_true')
autocreate_parser.add_argument('-o',
                               help='write scripts out to a designated directory',
                               nargs='?',
                               const='')
autocreate_parser.add_argument('-c', help='turn files into scripts', action='store_true')
autocreate_parser.add_argument('--skip-lines',
                               help='skip a set number of lines before processing data',
                               nargs=1,
                               type=int)
# retriever Install {Engine} ..
# retriever download [options]
install_subparsers = install_parser.add_subparsers(help='engine-specific help',
                                                   dest='engine')

for engine in engine_list:
    if engine.name == "Download Only":
        # download engine follows, retriever download [dataset]
        download_parser.add_argument(
            'dataset', help='dataset name').completer = ChoicesCompleter(script_list)
    else:
        engine_parser = install_subparsers.add_parser(engine.abbreviation,
                                                      help=engine.name)
        engine_parser.add_argument(
            'dataset', help='dataset name').completer = ChoicesCompleter(script_list)
        engine_parser.add_argument(
            '--hash-value',
            help='install dataset from provenance directory using hash value',
            default=None,
            required=False,
            type=str)
        engine_parser.add_argument('-b',
                                   '--bbox',
                                   nargs=4,
                                   help='Set bounding box xmin, ymin, xmax, ymax',
                                   required=False)
        if engine.name == "JSON":
            engine_parser.add_argument('-p',
                                       '--pretty',
                                       help='Add indentation to json file',
                                       action='store_true',
                                       required=False)

    abbreviations = set('h')

    for arg in engine.required_opts:
        arg_name, help_msg, default = arg[:3]
        potential_abbreviations = [char for char in arg_name if char not in abbreviations]
        if potential_abbreviations:
            abbreviation = potential_abbreviations[0]
            abbreviations.add(abbreviation)
        else:
            abbreviation = '-%s' % arg_name

        if engine.name == "Download Only" or abbreviation == "download":
            # add attributes to Download only engine
            download_parser.add_argument('--%s' % arg_name,
                                         '-%s' % abbreviation,
                                         help=help_msg,
                                         nargs='?',
                                         default=default)
        else:
            engine_parser.add_argument('--%s' % arg_name,
                                       '-%s' % abbreviation,
                                       help=help_msg,
                                       nargs='?',
                                       default=default)

argcomplete.autocomplete(parser)
