# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.


import os
import subprocess
import tempfile
from argparse import ArgumentParser

from .task_config import all_task_configs

COMMON_ARGUMENT_GROUPS = {
    "push": [
        [
            ["-m", "--message"],
            {
                "const": "editor",
                "default": "{msg}",
                "nargs": "?",
                "help": "Use the specified commit message, or create it in your "
                "$EDITOR if blank. Defaults to computed message.",
            },
        ],
        [
            ["--closed-tree"],
            {
                "action": "store_true",
                "default": False,
                "help": "Push despite a closed try tree",
            },
        ],
        [
            ["--push-to-vcs"],
            {
                "action": "store_true",
                "default": False,
                "help": (
                    "Submit changes directly to VCS instead of Lando. "
                    "Set `MACH_TRY_PUSH_TO_VCS=1` in the environment to force this."
                ),
            },
        ],
    ],
    "preset": [
        [
            ["--save"],
            {
                "default": None,
                "help": "Save selection for future use with --preset.",
            },
        ],
        [
            ["--preset"],
            {
                "default": None,
                "help": "Load a saved selection.",
            },
        ],
        [
            ["--list-presets"],
            {
                "action": "store_const",
                "dest": "preset_action",
                "const": "list",
                "default": None,
                "help": "List available preset selections.",
            },
        ],
        [
            ["--edit-presets"],
            {
                "action": "store_const",
                "dest": "preset_action",
                "const": "edit",
                "default": None,
                "help": "Edit the preset file.",
            },
        ],
    ],
    "task": [
        [
            ["--full"],
            {
                "action": "store_true",
                "default": False,
                "help": "Use the full set of tasks as input to fzf (instead of "
                "target tasks).",
            },
        ],
        [
            ["-p", "--parameters"],
            {
                "default": None,
                "help": "Use the given parameters.yml to generate tasks, "
                "defaults to a default set of parameters",
            },
        ],
    ],
}

NO_PUSH_ARGUMENT_GROUP = [
    [
        ["--stage-changes"],
        {
            "dest": "stage_changes",
            "action": "store_true",
            "help": "Locally stage changes created by this command but do not "
            "push to try.",
        },
    ],
    [
        ["--no-push"],
        {
            "dest": "dry_run",
            "action": "store_true",
            "help": "Do not push to try as a result of running this command (if "
            "specified this command will only print calculated task "
            "selection info and not change files).",
        },
    ],
]


class BaseTryParser(ArgumentParser):
    name = "try"
    common_groups = ["push", "preset"]
    arguments = []
    task_configs = []

    def __init__(self, *args, **kwargs):
        ArgumentParser.__init__(self, *args, **kwargs)

        group = self.add_argument_group(f"{self.name} arguments")
        for cli, kwargs in self.arguments:
            group.add_argument(*cli, **kwargs)

        for name in self.common_groups:
            group = self.add_argument_group(f"{name} arguments")
            arguments = COMMON_ARGUMENT_GROUPS[name]

            # Preset arguments are all mutually exclusive.
            if name == "preset":
                group = group.add_mutually_exclusive_group()

            for cli, kwargs in arguments:
                group.add_argument(*cli, **kwargs)

            if name == "push":
                group_no_push = group.add_mutually_exclusive_group()
                arguments = NO_PUSH_ARGUMENT_GROUP
                for cli, kwargs in arguments:
                    group_no_push.add_argument(*cli, **kwargs)

        group = self.add_argument_group("task configuration arguments")
        self.task_configs = {c: all_task_configs[c]() for c in self.task_configs}
        for cfg in self.task_configs.values():
            cfg.add_arguments(group)

    def validate(self, args):
        if hasattr(args, "message"):
            if args.message == "editor":
                if "EDITOR" not in os.environ:
                    self.error(
                        "must set the $EDITOR environment variable to use blank --message"
                    )

                with tempfile.NamedTemporaryFile(mode="r") as fh:
                    subprocess.call([os.environ["EDITOR"], fh.name])
                    args.message = fh.read().strip()

            if "{msg}" not in args.message:
                args.message = "{}\n\n{}".format(args.message, "{msg}")

    def parse_known_args(self, *args, **kwargs):
        args, remainder = ArgumentParser.parse_known_args(self, *args, **kwargs)
        self.validate(args)
        return args, remainder
