#! /usr/bin/python3

import sys
import argparse
from pathlib import Path
from jinja2 import Environment, select_autoescape, FileSystemLoader

import pal_app

PKG_PATH = Path(pal_app.__file__).parent.parent.parent.parent.parent / "share"

AVAILABLE_TEMPLATES = {
    "python": {
        "tpl_path": "python_script",
        "short_desc": "simple Python script",
        "post_install_help": "Edit ./{path}/src/{id}/application_controller.py to implement your application logic.",
    }
}

AVAILABLE_ROBOTS = ["ARI"]

TPL_EXT = "j2"


def get_intents():

    intents = []

    try:
        import rosmsg
    except ImportError:
        print(
            "rosmsg not installed -- we can not automatically generate the list of available intents"
        )
        return intents

    try:
        msg_def = rosmsg.get_msg_text("hri_actions_msgs/Intent", raw=True).split("\n")
    except Exception:
        print(
            "ROS Intent.msg not found. You can install it with 'apt install ros-noetic-hri-actions-msgs'.\nFor now, not generating the list of available intents."
        )
        return intents

    table = []
    in_table = False

    for l in msg_def:
        if "BEGIN_INTENTS_TABLE" in l:
            in_table = True
            continue
        if "END_INTENTS_TABLE" in l:
            break
        if in_table and "|" in l:
            table.append(l)

    if not table:
        print(
            "Intent.msg not found or empty :-( Not generating the intents handling code"
        )
        return intents

    header = [
        h.strip(" *").lower().replace(" ", "_") for h in table[0].split("|")[1:-1]
    ]

    for l in table[1:]:
        entries = [e.strip(" `") for e in l.split("|")[1:-1]]

        # required thematic roles
        entries[2] = [x.strip().replace("`", "") for x in entries[2].split("-")[1:]]
        # optional thematic roles
        entries[3] = [x.strip().replace("`", "") for x in entries[3].split("-")[1:]]

        if not entries[0]:  # intent spanning multiple rows
            additional_data = dict(zip(header, entries))
            for h in header:
                intents[-1][h] += additional_data[h]
        else:
            intents.append(dict(zip(header, entries)))

    return intents


def interactive_create(id=None, template=None, robot=None):

    while not id:
        id = input(
            "ID of your application? (must be a vlid identifier without spaces. eg 'robot_receptionist')\n"
        )

    name = input(
        "Full name of your application? (eg 'The Receptionist Robot', press Return to skip)\n"
    )
    if not name:
        name = id

    while not robot:
        print("\nWhat robot are you targeting?")
        for idx, r in enumerate(AVAILABLE_ROBOTS):
            print("%s: %s" % (idx + 1, r))

        try:
            choice = int(input("\nYour choice? "))

            robot = AVAILABLE_ROBOTS[choice - 1]
        except:
            robot = ""

    while not template:
        print("\nWhat kind of application controller do you want to create?")
        for idx, tpl in enumerate(AVAILABLE_TEMPLATES.keys()):
            print("%s: %s" % (idx + 1, AVAILABLE_TEMPLATES[tpl]["short_desc"]))

        try:
            choice = int(input("\nYour choice? "))

            template = list(AVAILABLE_TEMPLATES.keys())[choice - 1]
        except:
            template = ""
    return id, name, template, robot


if __name__ == "__main__":

    parser = argparse.ArgumentParser(
        description="Generate and manage application skeletons for ROS-based robots"
    )
    #     parser.add_argument(
    #         "-f",
    #         "--force",
    #         action="store_true",
    #         help="if set, force overwriting existing documentation",
    #     )
    #

    subparsers = parser.add_subparsers(dest="command")

    create_parser = subparsers.add_parser(
        "create", help="Create a new application skeleton"
    )
    create_parser.add_argument(
        "-i",
        "--id",
        type=str,
        nargs="?",
        help="ID of your application. Must be a valid file name without spaces.",
    )

    create_parser.add_argument(
        "-r",
        "--robot",
        choices=AVAILABLE_ROBOTS,
        type=str,
        nargs="?",
        help="target robot.",
    )

    create_parser.add_argument(
        "-t",
        "--template",
        choices=AVAILABLE_TEMPLATES.keys(),
        type=str,
        nargs="?",
        help="Template to use.",
    )

    create_parser.add_argument(
        "path",
        type=str,
        nargs="?",
        const=".",
        default=".",
        help="path of the directory where the skeleton will be generated (default: .)",
    )

    args = parser.parse_args()

    if not args.command:
        print("You must select a command.\nType 'pal_app --help' for details.")
        sys.exit(1)

    intents = get_intents()

    id, name, tpl, robot = interactive_create(args.id, args.template, args.robot)

    data = {"id": id, "name": name, "intents": intents, "robot": robot}

    root = Path(args.path) / id
    root.mkdir(parents=True, exist_ok=True)

    print("Generating application skeleton in %s..." % root)

    if tpl == "python":

        env = Environment(
            loader=FileSystemLoader(
                PKG_PATH / "tpl" / AVAILABLE_TEMPLATES[tpl]["tpl_path"]
            ),
            autoescape=select_autoescape(),
            trim_blocks=True,
        )

        tpls = env.list_templates(extensions=TPL_EXT)

        for tpl_name in tpls:
            j_tpl = env.get_template(tpl_name)
            tpl_name = tpl_name.replace("{{id}}", data["id"])
            filename = root / tpl_name[: -(1 + len(TPL_EXT))]
            filename.parent.mkdir(parents=True, exist_ok=True)
            print("Creating %s..." % filename)
            with open(filename, "w") as fh:
                fh.write(j_tpl.render(data))

        print("\n\033[32;1mDone!")
        print("\033[33;1m")
        print(AVAILABLE_TEMPLATES[tpl]["post_install_help"].format(path=root, id=id))
        print("\033[0m")

    else:
        print("No template for %s! Can not generate anything!" % tpl)
