from pathlib import Path
from typing import Any, Dict, Iterable, List, Mapping

from typing_extensions import Protocol, runtime_checkable


@runtime_checkable
class GetQuestions(Protocol):
    """
    The get_questions typing definition.
    """

    def __call__(
        self, *, template: str, folder_name: str
    ) -> Iterable[Mapping[str, Any]]:
        """
        Return a Questionary dictionary-type iterable.

        :param template: Name of the requested template.
        :param folder_name: Name of the top-level folder.
        :return: Dictionary of data passed to the template.
        """
        pass


@runtime_checkable
class FoldersToTemplate(Protocol):
    """
    The folders_to_template typing definition.
    """

    def __call__(
        self, *, template: str, folder_name: str, data: Dict[str, Any]
    ) -> List[str]:
        """
        Take all input and returns a list of folders within the plugin.

        These folders are used to specify which should be templated, and intended to
        support optional configuration.

        :param template: Name of the requested template.
        :param folder_name: Name of the top-level folder.
        :param data: Dictionary of data passed to the template.
        :return: List of folders to template.
        """
        pass


@runtime_checkable
class PreTemplateHook(Protocol):
    """
    The pre_template_hook typing definition.
    """

    def __call__(
        self, *, template: str, folder_name: str, data: Dict[str, Any]
    ) -> None:
        """
        Run before a plugin creates a template.

        This optional function is intended to be used to modify the data dictionary
        that's passed to Jinja2 for the templating.

        :param template: Name of the requested template.
        :param folder_name: Name of the top-level folder.
        :param data: Dictionary of data passed to the template.
        :return: Nothing
        """
        pass


@runtime_checkable
class PostTemplateHook(Protocol):
    """
    The post_template_hook typing definition.
    """

    def __call__(
        self,
        *,
        template: str,
        folder_name: str,
        output_folder: Path,
        data: Dict[str, Any]
    ) -> None:
        """
        Run after a plugin has successfully templated.

        This optional function is intended to be used to run steps after the templating
        has been run, and passes in the path to the final directory. This can be used
        to run CLI commands, or alter the folder data if wished.

        :param template: Name of the requested template.
        :param folder_name: Name of the top-level folder.
        :param output_folder: Path to the generated folder.
        :param data: Dictionary of data passed to the template.
        :return: Nothing
        """
        pass


def get_questions_decorator(func: GetQuestions) -> GetQuestions:
    """
    Decorate the get_questions plugin function.
    """
    return func


def folders_to_template_decorator(func: FoldersToTemplate) -> FoldersToTemplate:
    """
    Decorate the folders_to_template plugin function.
    """
    return func


def pre_template_hook_decorator(func: PreTemplateHook) -> PreTemplateHook:
    """
    Decorate the pre_template_hook plugin function.
    """
    return func


def post_template_hook_decorator(func: PostTemplateHook) -> PostTemplateHook:
    """
    Decorate the post_template_hook plugin function.
    """
    return func
