#!/usr/bin/python3
# pylint: disable=invalid-name  # https://github.com/PyCQA/pylint/issues/516

import sys
import os
import inspect
import urllib.request
import urllib.parse
import urllib.error
import argparse
import configparser
import logging

import argcomplete

import mini_buildd.misc
import mini_buildd.net
import mini_buildd.config
import mini_buildd.api

LOG = logging.getLogger("mini_buildd")
mini_buildd.misc.setup_console_logging(logging.DEBUG)


def endpoint_completer(_prefix, **_kwargs):
    """Ugly-parse a list of host names from ~/.dput.cf (solely for shell autocompletion convenience)."""
    hosts = []
    try:
        dput_cf = configparser.ConfigParser(interpolation=None)
        dput_cf.read(os.path.expanduser("~/.dput.cf"))
        for section in dput_cf.sections():
            def _join(host, user):
                return f"{user}@{host}" if user else host

            config = dput_cf[section]
            host = config.get("x_mini_buildd_host")
            if host:
                for u in [None, "admin", os.getenv("USER")] + config.get("x_mini_buildd_users", "").split():
                    if section.startswith("mini-buildd-"):
                        hosts.append(_join(section[12:], u))
                    else:
                        hosts.append(_join(section, u))
    except BaseException as e:
        LOG.info(f"Error endpoint_completer (ignoring): {e}")

    return hosts


def endpoint_from_dput(section):
    dput_cf = configparser.RawConfigParser()
    dput_cf.read(os.path.expanduser("~/.dput.cf"))
    try:
        return dput_cf.get("mini-buildd-" + section, "x_mini_buildd_host")
    except BaseException:
        return dput_cf.get(section, "x_mini_buildd_host")


PARSER = argparse.ArgumentParser(prog="mini-buildd-tool",
                                 description="Command line tool to run API calls.",
                                 epilog="Note: Uses 'python-keyring' to persist passwords (see '~/.local/share/python_keyring/')",
                                 formatter_class=mini_buildd.misc.ArgumentDefaultsRawTextHelpFormatter)


PARSER.add_argument("--version", action="version", version=mini_buildd.__version__)
PARSER.add_argument("-v", "--verbose", dest="verbosity", action="count", default=0,
                    help="increase log level. Give twice for max logs")
PARSER.add_argument("-q", "--quiet", dest="terseness", action="count", default=0,
                    help="decrease log level. Give twice for min logs")
PARSER.add_argument("-J", "--json", action="store_true",
                    help="use parsable json output")
PARSER.add_argument("--auto-confirm", action="store_true",
                    help="force-bypass extra confirmation (for confirmable commands)")
PARSER.add_argument("endpoint", action="store",
                    metavar="ENDPOINT",
                    help=f"HTTP target endpoint: {inspect.getdoc(mini_buildd.net.ClientEndpoint)}\n\nMay also be '[user@]DPUT_TARGET' for convenience").completer = endpoint_completer


def cmd_call(args):
    # Log in if user given explicitly, or required by the command
    client = mini_buildd.api.Client(args.endpoint, auto_confirm=args.auto_confirm)

    # Compute api call parameters
    arg_identities = mini_buildd.api.COMMANDS[args.command].arg_identities()
    http_args = {}
    for k in [k for k in list(args.__dict__.keys()) if k in arg_identities]:
        if args.__dict__[k] is not None:
            http_args[k] = args.__dict__[k]

    # Run call
    print(client.call(args.command, http_args, plain=not args.json))


# Unfortunaetely, we cannot group the commands (yet), see http://bugs.python.org/issue14037, https://bugs.python.org/issue9341
SUBPARSERS = PARSER.add_subparsers(title="API commands (run 'mini-buildd-tool '' <cmd> --help' for full command help)",
                                   required=True,
                                   metavar="<cmd> [options]")
for cmd, cmd_cls in mini_buildd.api.COMMANDS.items():
    if not cmd_cls.isgroup():
        cmd_parser = SUBPARSERS.add_parser(cmd, help=cmd_cls.doc())
        for argument in cmd_cls.ARGUMENTS:
            cmd_parser.add_argument(*argument.id_list, **argument.argparse_kvsargs)
        cmd_parser.set_defaults(func=cmd_call, command=cmd, command_class=cmd_cls)


# Parse and run
argcomplete.autocomplete(PARSER)
ARGS = PARSER.parse_args()
LOG.setLevel(logging.WARNING - (10 * (min(2, ARGS.verbosity) - min(2, ARGS.terseness))))

if LOG.getEffectiveLevel() <= logging.DEBUG:
    mini_buildd.config.DEBUG = ["exception"]
mini_buildd.misc.clone_log("keyring")

try:
    ARGS.func(ARGS)
except urllib.error.HTTPError as e:
    mini_buildd.config.log_exception(LOG, ARGS.endpoint, e)
    sys.exit(1)
except BaseException as e:
    mini_buildd.config.log_exception(LOG, f"{ARGS.endpoint}", e)
    sys.exit(2)
