from __future__ import absolute_import, division, print_function, unicode_literals

import inspect
import pkgutil
import sys

from .added_command import AddedCommand
from .api import autogenerated, composite_commands
from .argument_parser import NonPrintingParser
from .error import PrintingException


class CLI:
    """Class for interacting with users through a CLI."""

    def __init__(self, test_api_path=None):
        """Initialize the CLI API."""
        self.parser = NonPrintingParser()  # Need to add description based on spec.
        self.commands = {}
        subparsers = self.parser.add_subparsers(help='sub-command help')
        prefix = autogenerated.__name__ + "."
        for importer, modname, _ in pkgutil.iter_modules(autogenerated.__path__, prefix):
            self._add_parsers(importer, modname, subparsers)

        prefix = composite_commands.__name__ + "."
        for importer, modname, _ in pkgutil.iter_modules(composite_commands.__path__, prefix):
            self._add_parsers(importer, modname, subparsers)

    def _add_parsers(self, importer, modname, subparsers):
        module = importer.find_module(modname).load_module(modname)
        clsmembers = inspect.getmembers(module, inspect.isclass)

        command_class = None
        for class_ in clsmembers:
            if class_[0] != AddedCommand.__name__:
                command_class = class_[1]

        command_class.add_parser(subparsers)
        self.commands[command_class.get_command_name()] = command_class

    def parse_args(self, command_line_input):
        """Parse the input arguments into a map from parameter name -> value."""
        args = vars(self.parser.parse_args(command_line_input))
        args = {k: args[k] for k in args if args[k] is not None}
        return args

    def make_request(self, command_line_input, stream=False):
        """Function to actually make request to api."""
        if not command_line_input:
            return self.parser.format_help()

        # Handles PrintingException if Base ArgumentParser was going to print.
        try:
            args = self.parse_args(command_line_input)
        except PrintingException as pe:
            msg = pe.args[0]
            return msg

        endpoint = command_line_input[0]

        command = self.commands.get(endpoint, None)
        if command:
            return command.run_from_cli(args)
        return Exception("This command doesn't exist!")


if __name__ == "__main__":
    cli = CLI()
    response = cli.make_request(sys.argv[1:])
    if response:
        print(response.headers)
        print(response.content)
