import logging
import re

from rpdk.core.exceptions import WizardAbortError, WizardValidationError
from rpdk.core.plugin_registry import get_plugin_choices
from rpdk.core.utils.init_utils import input_with_validation, print_error

LOG = logging.getLogger(__name__)
RESOURCE_TYPE_NAME_REGEX = r"^[a-zA-Z0-9]{2,64}::[a-zA-Z0-9]{2,64}::[a-zA-Z0-9]{2,64}$"


def init_resource(args, project):
    if args.type_name:
        try:
            type_name = validate_type_name(args.type_name)
        except WizardValidationError as error:
            print_error(error)
            type_name = input_typename()
    else:
        type_name = input_typename()

    if "language" in vars(args):
        language = args.language.lower()
    else:
        language = input_language()

    settings = {
        arg: getattr(args, arg)
        for arg in vars(args)
        if not callable(getattr(args, arg))
    }

    project.init(type_name, language, settings)
    project.generate()
    project.generate_docs()


def input_typename():
    type_name = input_with_validation(
        "What's the name of your resource type?",
        validate_type_name,
        "\n(Organization::Service::Resource)",
    )
    LOG.debug("Resource type identifier: %s", type_name)
    return type_name


def input_language():
    # language/plugin
    if validate_plugin_choice.max < 1:
        LOG.critical("No language plugins found")
        raise WizardAbortError()

    if validate_plugin_choice.max == 1:
        language = validate_plugin_choice.choices[0]
        LOG.warning("One language plugin found, defaulting to %s", language)
    else:
        language = input_with_validation(
            validate_plugin_choice.message, validate_plugin_choice
        )
    LOG.debug("Language plugin: %s", language)
    return language


def validate_type_name(value):
    match = re.match(RESOURCE_TYPE_NAME_REGEX, value)
    if match:
        return value
    LOG.debug("'%s' did not match '%s'", value, RESOURCE_TYPE_NAME_REGEX)
    raise WizardValidationError(
        "Please enter a value matching '{}'".format(RESOURCE_TYPE_NAME_REGEX)
    )


class ValidatePluginChoice:
    def __init__(self, choices):
        self.choices = tuple(choices)
        self.max = len(self.choices)

        pretty = "\n".join(
            "[{}] {}".format(i, choice) for i, choice in enumerate(self.choices, 1)
        )
        self.message = (
            "Select a language for code generation:\n"
            + pretty
            + "\n(enter an integer): "
        )

    def __call__(self, value):
        try:
            choice = int(value)
        except ValueError as e:
            raise WizardValidationError("Please enter an integer") from e
        choice -= 1
        if choice < 0 or choice >= self.max:
            raise WizardValidationError("Please select a choice")
        return self.choices[choice]


validate_plugin_choice = ValidatePluginChoice(  # pylint: disable=invalid-name
    get_plugin_choices()
)
