#!/usr/bin/env python

__author__ = "Vanessa Sochat"
__copyright__ = "Copyright 2022, Vanessa Sochat"
__license__ = "MPL 2.0"

import argparse
import os
import sys

import citelang
from citelang.logger import setup_logger


def get_parser():
    parser = argparse.ArgumentParser(
        description="CiteLang",
        formatter_class=argparse.RawTextHelpFormatter,
    )

    # Global Variables
    parser.add_argument(
        "--debug",
        dest="debug",
        help="use verbose logging to debug.",
        default=False,
        action="store_true",
    )

    parser.add_argument(
        "--quiet",
        dest="quiet",
        help="suppress additional output.",
        default=False,
        action="store_true",
    )

    parser.add_argument(
        "--no-cache",
        dest="no_cache",
        help="disable using the cache for any particular command.",
        default=False,
        action="store_true",
    )

    parser.add_argument(
        "--version",
        dest="version",
        help="show software version.",
        default=False,
        action="store_true",
    )

    description = "actions"
    subparsers = parser.add_subparsers(
        help="actions",
        title="actions",
        description=description,
        dest="command",
    )

    # print version and exit
    subparsers.add_parser("version", description="show software version")

    # List package managers available
    ls = subparsers.add_parser(
        "list", description="list package managers available to derive citations from."
    )
    ls.add_argument("--json", help="output json", default=False, action="store_true")
    ls.add_argument("--all", help="output json", default=False, action="store_true")
    ls.add_argument("--outfile", "-o", help="write content to output file")

    # Cache control
    cache = subparsers.add_parser("cache", description="cache control")
    cache.add_argument(
        "--clear", help="clear the cache", default=False, action="store_true"
    )

    # Get a package or dependencies
    pkg = subparsers.add_parser(
        "package",
        description="list package managers available to derive citations from.",
    )
    deps = subparsers.add_parser("deps", description="list dependencies for a package.")

    # Extract contributions from a GitHub repo
    contrib = subparsers.add_parser(
        "contrib", description="Extract data for git contributions."
    )
    contrib.add_argument(
        "--outdir",
        "-d",
        help="output directory for data (defaults to .contrib)",
        default=os.path.join(os.getcwd(), ".contrib"),
    )
    contrib.add_argument("--outfile", "-o", help="Save to an output json file.")
    contrib.add_argument(
        "--start",
        "-s",
        help="start commit or tag to parse (defaults to start of history)",
    )
    contrib.add_argument(
        "--end",
        "-e",
        help="end commit or tag to parse (defaults to end of history)",
    )
    contrib.add_argument(
        "--root",
        "-r",
        help="Location where .git directory resides (defaults to PWD)",
        default=os.getcwd(),
    )
    contrib.add_argument(
        "--by",
        "-b",
        help="Organize results BY this attribute (author, path)",
        default="author",
        choices=["author", "path"],
    )
    contrib.add_argument(
        "--detail",
        help="include contribution details",
        default=False,
        action="store_true",
    )
    contrib.add_argument(
        "--shallow",
        help="Only look at the --first-parent and try to summarize copies and movements.",
        default=False,
        action="store_true",
    )
    contrib.add_argument(
        "--all-time",
        help="include blame from all time, not just within range.",
        default=False,
        action="store_true",
    )
    contrib.add_argument(
        "--filters",
        help="A filters yaml file, optionally with an authors key (key value pairs of an author name, and the alias to use) and an ignore key (list of author names to not include).",
    )

    badge = subparsers.add_parser(
        "badge", description="Generate an html (svg-based) badge."
    )
    badge.add_argument(
        "--template",
        "-t",
        help="Template to use for badge",
        choices=["treemap", "sunburst", "static"],
        default="static",
    )

    for command in [cache, badge]:
        command.add_argument(
            "--force",
            help="do not ask for confirmation",
            default=False,
            action="store_true",
        )

    graph = subparsers.add_parser(
        "graph", description="generate a graph for some package dependencies."
    )
    graph.add_argument(
        "--fmt", "-f", help="format of the graph (unset defaults to console print)"
    )
    credit = subparsers.add_parser(
        "credit", description="calculate dependency credit for a package."
    )
    gen = subparsers.add_parser(
        "gen", description="Generate a credit markdown file for a package of choice."
    )
    gen.add_argument("--outfile", "-o", help="Save to an output markdown file.")

    render = subparsers.add_parser(
        "render", description="render a credit tree into your markdown."
    )
    render.add_argument("filename", help="Markdown file to render software table into.")
    render.add_argument("--outfile", "-o", help="Save to an output json file.")

    for command in [pkg, deps, graph, credit, badge, gen]:
        command.add_argument(
            "package", help="package manager and name to parse", nargs=2
        )

    for command in [pkg, deps, graph, credit, badge]:
        command.add_argument(
            "--json",
            dest="json",
            help="print output to json.",
            default=False,
            action="store_true",
        )
        command.add_argument("--outfile", "-o", help="Save to an output json file.")

    for command in [graph, credit, badge, render, gen]:
        command.add_argument(
            "--max-depth", help="maximum depth to parse tree (default is unset)"
        )
        command.add_argument(
            "--max-deps",
            help="maximum number of dependencies to include (default is unset)",
        )
        command.add_argument(
            "--min-credit",
            help="minimum credit to allocate (and stop when lower)",
            type=float,
            default=0.01,
        )
        command.add_argument(
            "--credit-split",
            help="credit to allocate to main package and 1-split to dependents",
            type=float,
            default=0.5,
        )

    # Local shell with client loaded
    shell = subparsers.add_parser(
        "shell",
        description="shell into a Python session with a client.",
        formatter_class=argparse.RawTextHelpFormatter,
    )
    shell.add_argument(
        "--interpreter",
        "-i",
        dest="interpreter",
        help="python interpreter",
        choices=["ipython", "python", "bpython"],
        default="ipython",
    )

    # Custom config
    config = subparsers.add_parser(
        "config",
        description="update configuration settings. Use set or get to see or set information.",
        formatter_class=argparse.RawTextHelpFormatter,
    )

    config.add_argument(
        "--central",
        dest="central",
        help="make edits to the central config file.",
        default=False,
        action="store_true",
    )

    config.add_argument(
        "params",
        nargs="*",
        help="""Set or get a config value, edit the config, add or remove a list variable, or create a user-specific config.
citelang config set key:value
citelang config get key
citelang edit
citelang config inituser""",
        type=str,
    )
    return parser


def run():

    parser = get_parser()

    def help(return_code=0):
        version = citelang.__version__

        print("\nCiteLang Client v%s" % version)
        parser.print_help()
        sys.exit(return_code)

    # If the user didn't provide any arguments, show the full help
    if len(sys.argv) == 1:
        help()

    # If an error occurs while parsing the arguments, the interpreter will exit with value 2
    args, extra = parser.parse_known_args()

    if args.debug is True:
        os.environ["MESSAGELEVEL"] = "DEBUG"

    # Show the version and exit
    if args.command == "version" or args.version:
        print(citelang.__version__)
        sys.exit(0)

    setup_logger(
        quiet=args.quiet,
        debug=args.debug,
    )

    # retrieve subparser (with help) from parser
    helper = None
    subparsers_actions = [
        action
        for action in parser._actions
        if isinstance(action, argparse._SubParsersAction)
    ]
    for subparsers_action in subparsers_actions:
        for choice, subparser in subparsers_action.choices.items():
            if choice == args.command:
                helper = subparser
                break

    if args.command == "badge":
        from .badge import main
    elif args.command == "cache":
        from .cache import main
    elif args.command == "config":
        from .config import main
    elif args.command == "contrib":
        from .contrib import main
    elif args.command == "credit":
        from .credit import main
    elif args.command == "deps":
        from .deps import main
    elif args.command == "gen":
        from .gen import main
    elif args.command == "graph":
        from .graph import main
    elif args.command == "render":
        from .render import main
    elif args.command == "shell":
        from .shell import main
    elif args.command == "list":
        from .listing import main
    elif args.command == "package":
        from .package import main

    # Pass on to the correct parser
    return_code = 0
    try:
        main(args=args, parser=parser, extra=extra, subparser=helper)
        sys.exit(return_code)
    except UnboundLocalError:
        return_code = 1

    help(return_code)


if __name__ == "__main__":
    run()
