"""This module is for the handler interfaces'
validation implementations.
"""

import inspect
from inspect import Signature
from typing import Any
from typing import Callable
from typing import List


def validate_options_type(*, options: Any, additional_err_msg: str = "") -> None:
    """
    Validate a specified options type.

    Parameters
    ----------
    options : Any
        Target options value.
    additional_err_msg : str, optional
        An additional error message to display.

    Raises
    ------
    TypeError
        If a specified options type is not the dictionary or None.
    """
    if options is None:
        return
    if isinstance(options, dict):
        return
    if additional_err_msg != "":
        additional_err_msg = f"\n{additional_err_msg}"
    raise TypeError(
        f"Handler's options argument must be a dictionary: {type(options)}"
        f"\n{options}{additional_err_msg}"
    )


def validate_handler_args_num(
    *, handler: Callable, additional_err_msg: str = ""
) -> None:
    """
    Validate specified handler's arguments number.

    Parameters
    ----------
    handler : Callable
        A target handler to validate.
    additional_err_msg : str, optional
        An additional error message to display.

    Raises
    ------
    ValueError
        - If handler's arguments number is not 2.
    TypeError
        - If a specified handler is not callable.
    """
    if not callable(handler):
        raise TypeError(
            "A specified handler's argument is not callable: " f"{type(handler)}"
        )
    signature: Signature = inspect.signature(obj=handler)
    args_num: int = 0
    skipping_arg_names: List[str] = ["*", "**", "self", "cls"]
    arg_names: List[str] = []
    for parameter in signature.parameters:
        if parameter in skipping_arg_names:
            continue
        args_num += 1
        arg_names.append(parameter)
    if args_num != 2:
        if additional_err_msg != "":
            additional_err_msg = f"\n{additional_err_msg}"
        raise ValueError(
            "A specified handler's arguments number must be 2 "
            f"(actual: {args_num})"
            f"\nTarget argument names: {arg_names}"
            "\n\nThe first argument becomes event instance and the second "
            "one becomes the handler's option parameters."
            f"{additional_err_msg}"
        )
