__author__ = "PyPSA meets Earth"
__copyright__ = "Copyright 2022, The PyPSA meets Earth Initiative"
__license__ = "MIT"

"""CLI interface for earth_osm project.

This module provides a CLI interface for the earth_osm project.

"""

import argparse
import os

from earth_osm.config import primary_feature_element
from earth_osm.eo import get_osm_data
from earth_osm.gfk_data import get_all_valid_list, view_regions


def main():  # pragma: no cover
    """
    The main function executes on commands:
    `python -m earth_osm` and `$ earth_osm `.
    It parses the command line and executes the appropriate function.
    """

    class _HelpAction(argparse._HelpAction):
        def __call__(self, parser, namespace, values, option_string=None):
            parser.print_help()

            # retrieve subparsers from parser
            subparsers_actions = [
                action
                for action in parser._actions
                if isinstance(action, argparse._SubParsersAction)
            ]

            for subparsers_action in subparsers_actions:
                # get all subparsers and print help
                for choice, subparser in subparsers_action.choices.items():
                    print("Subparser '{}'".format(choice))
                    print(subparser.format_help())

            parser.exit()

    # Argparser Notes
    # '+' == 1 or more.
    # '*' == 0 or more.
    # '?' == 0 or 1.

    parser = argparse.ArgumentParser(
        description='Earth-OSM by PyPSA-meets-Earth',
        # epilog='''Example:''',
        add_help=False) # hide default help

    parser.add_argument('-h', '--help', action=_HelpAction,
                        help='earth-osm help')
    parser.add_argument('-v', '--version', action='version',
                        version='%(prog)s 0.1.0')

    subparser = parser.add_subparsers(dest='command', required=True, title='Sub Parser', description='''View Supported Regions or Extract OSM Data''')

    extract_parser = subparser.add_parser('extract', help='Extract OSM Data')

    extract_parser.add_argument('primary', choices=primary_feature_element.keys(), type=str, help='Primary Feature')

    # region_group = extract_parser.add_mutually_exclusive_group(required=True) # Get regions using ids or coordinates
    # region_group.add_argument('--regions',nargs="+", type=str, help='Region Identifier')
    # region_group.add_argument('--coords', nargs='+', type=float, help='Region Bounds') #TODO: Change to >3

    extract_parser.add_argument('--regions', nargs="+", type=str, help='Region Identifier') # TODO: replace with region group
    extract_parser.add_argument('--features', nargs="*", type=str, help='Sub-Features')
    extract_parser.add_argument('--update', action='store_true', default=False, help='Update Data')
    extract_parser.add_argument('--mp',  action='store_true', default=True, help='Use Multiprocessing')
    extract_parser.add_argument('--data_dir', nargs="?", type=str, help='Earth Data Directory')
    extract_parser.add_argument('--out_format', nargs="+", type=str, help='Export options')
    extract_parser.add_argument('--out_aggregate', action='store_true', default=False, help='Aggregate Outputs')
    
    view_parser = subparser.add_parser('view', help='View OSM Data')
    view_parser.add_argument('type', help='View Supported', choices=['regions', 'primary'])

    args = parser.parse_args()

    print("\n".join(["",
        "  _   _   _   _   _   _   _   _   _",
        " / \ / \ / \ / \ / \ / \ / \ / \ / \ ",
        "( E | a | r | t | h | - | O | S | M )",
        " \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ "]))

    if args.command == 'view':
        print('Viewing OSM Data')
        view_regions(level=0)
    elif args.command == 'extract':
        if args.regions:
            region_list = list(args.regions)
            if not set(region_list) <= set(get_all_valid_list()):
                raise KeyError(f'Invalid Region {" ".join(set(region_list) - set(get_all_valid_list()))} , run earth_osm view regions to view valid regions')
        # elif args.coords:
        #     # TODO: change coords to shapely polygon, implement geom=True, get regions that way
        #     raise NotImplementedError('Bounding Box Region Identifier Not Implemented')
        if args.out_format:
            out_format = set(args.out_format)
            if not out_format.issubset(['csv', 'geojson']):
                raise KeyError(f'Contains invalid format. Valid formats are: csv, geojson')

        if args.features:
            feature_list = list(args.features)
            if not set(feature_list) <= set(primary_feature_element[args.primary]):
                raise KeyError(f'Invalid Feature {" ".join(set(feature_list) - set(primary_feature_element[args.primary]))}, run earth_osm view features to view valid features')
        else:
            feature_list = primary_feature_element[args.primary]

        if args.data_dir:
            if not os.path.exists(args.data_dir):
                os.makedirs(args.data_dir, exist_ok=True)
            if os.path.isdir(args.data_dir):
                data_dir = args.data_dir
            else:
                raise NotADirectoryError(f'Invalid Data Directory {args.data_dir}')
        else:
            data_dir = os.path.join(os.getcwd(), 'earth_data')

        print('\n'.join(['',
            f'Primary Feature: {args.primary}',
            f'Sub Features: {" - ".join(feature_list)}',
            f'Regions: {" - ".join(region_list)}',
            f'Multiprocessing = {args.mp}',
            f'Update Data = {args.update}',
            f'Data Directory = {data_dir}',
            f'Output Format = {" - ".join(out_format)}',
            f'Aggregate Outputs = {args.out_aggregate}',
            ]))

        get_osm_data(
            region_list=region_list,
            primary_name=args.primary,
            feature_list=feature_list,
            update=args.update,
            mp=args.mp,
            data_dir=data_dir,
            out_format=out_format,
            out_aggregate=args.out_aggregate,
        )

    else:
        # import inquirer #https://github.com/magmax/python-inquirer
        raise NotImplementedError('Interactive Mode Not Implemented')


