import click

def print_completion_spec(cli):
    spec = generate_completion_spec(cli)
    print(spec)

def generate_completion_spec(cli):
    with click.Context(cli) as ctx:
        info = ctx.to_info_dict()
        out = generate_command(info["command"])
        return get_template(out)

def get_value(dict, keys):
    for key in keys:
        value = dict[key]
        if value:
            return value

    return None

def flatten(t):
    return [item for sublist in t for item in sublist]

def generate_options(option):
    # if option.hidden:
    #     return None

    opt = {
        "name": option["opts"],
    }

    if option["help"]:
        opt["description"] = option["help"]

    if option["required"]:
        opt["isRequired"] = True

    if option["multiple"]:
        opt["isRepeatable"] = True

    if hasattr(option, "deprecated"):
        opt["deprecated"] = True

    if not option["is_flag"]:
        opt["args"] = generate_args(option["type"], option["nargs"])

    if len(option["secondary_opts"]) > 0:
        inverse = opt.copy()
        inverse["name"] = option["secondary_opts"]
        return [
            opt,
            inverse
        ]

    return [ opt ]

# https://click.palletsprojects.com/en/8.0.x/parameters/
def generate_args(info, nargs):
    param_type = info["param_type"]

    arg = {
        "name": info.get("name", "argument")
    }

    if param_type == "Choice":
        arg["suggestions"] = info["choices"]
    elif param_type == "Tuple":
        return list(map(lambda raw: { "name": raw["name"] }, info["types"]) or [])
    elif param_type == "File":
        arg["template"] = "filepaths"
    elif param_type == "Path":


        templates = []

        if info["dir_okay"]:
            templates.append("folders")
        if info["file_okay"]:
            templates.append("filepaths")

        if len(templates) > 0:
            arg["template"] = templates

        if not info["exists"]:
            arg["suggestCurrentToken"] = True


    if nargs == -1:
        arg["isVariadic"] = True
        nargs = 1
    
    return [ arg ] * nargs


def generate_command(command):
    command_name = command.get("name", "")
    integration_command_name = "dumphelp"
    if command_name == integration_command_name:
        return None

    spec = {
        "name": command_name,
        "description": get_value(command, ["short_help", "help"]) or ""
    }

    # get options
    raw_options = filter(lambda param: param["param_type_name"] == "option", command.get("params", []))

    options = flatten(list(map(lambda raw: generate_options(raw), raw_options) or []))
    if len(options) > 0:
        spec["options"] = options

    # get args
    raw_args = filter(lambda param: param["param_type_name"] == "argument", command.get("params", []))
    args = list(map(lambda raw: generate_args(raw["type"], raw["nargs"]), raw_args or []))

    if len(args) > 0:
        spec["args"] = args


    # get subcommands
    subcommands = list(map(lambda raw: generate_command(raw), (command.get("commands", {})).values()))
    if len(subcommands) > 0:
        spec["subcommands"] = list(filter(lambda sub: sub != None, subcommands))

    return spec

def get_template(spec):
    return """
// Autogenerated by @fig/click
const completionSpec: Fig.Spec = {}

export default completionSpec;
""".format(json.dumps(spec, indent=2))