import re
from typing import Callable, TypeAlias
from .utils import safe_float
from .patterns import LIST


Number: TypeAlias = int | float


def is_list(pattern: re.Pattern = LIST) -> Callable[[str], bool]:
    """
    Generates a validator function that checks if a string matches a specific
    multi-item, space-separated list format.

    :param pattern: The regex pattern to apply using fullmatch().
                    The default pattern (LIST) requires the input to contain
                    a list of items separated by spaces (minimum two items).
    :return: A validator function (Callable[[str], bool]).
    """
    return lambda x: bool(pattern.fullmatch(x))


def is_in_list(options: list[str], case_sensitive: bool = True) -> Callable[[str], bool]:
    """
    Generates a validator function that checks if a string input is in list of options.

    :param options: list of valid strings.
    :param case_sensitive: If True, validation is case-sensitive;
                           if False, case is ignored during comparison.
    :return: A validator function Callable[[str], bool].
    """
    if case_sensitive:
        return lambda x: x in options
    else:
        return lambda x: x.lower() in [opt.lower() for opt in options]


def is_in_range(start: Number, end: Number) -> Callable[[str], bool]:
    """
    Generates a validator function that checks if a number (string input)
    is within the inclusive range [start, end].

    The generated validator safely attempts to convert the input string to a float
    before comparison.

    :param start: The lower bound (inclusive).
    :param end: The upper bound (inclusive).
    :return: A validator function (Callable[[str], bool]).
    """

    def validator(text: str) -> bool:
        number = safe_float(text)
        if number is None:
            return False
        return start <= number <= end

    return validator


def is_between(start: Number, end: Number) -> Callable[[str], bool]:
    """
    Generates a validator function that checks if a number (string input)
    is within the exclusive open interval (start, end).

    :param start: The lower bound (exclusive).
    :param end: The upper bound (exclusive).
    :return: A validator function (Callable[[str], bool]).
    """

    def validator(text: str) -> bool:
        number = safe_float(text)
        if number is None:
            return False
        return start < number < end

    return validator


def more(limit: Number) -> Callable[[str], bool]:
    """
    Generates a validator function that checks if a number (string input)
    is strictly greater than the limit (> limit).

    :param limit: The number to compare against (exclusive).
    :return: A validator function (Callable[[str], bool]).
    """

    def validator(text: str) -> bool:
        number = safe_float(text)
        if number is None:
            return False
        return number > limit

    return validator


def more_or_equal(limit: Number) -> Callable[[str], bool]:
    """
    Generates a validator function that checks if a number (string input)
    is greater than or equal to the limit (>= limit).

    :param limit: The number to compare against (inclusive).
    :return: A validator function (Callable[[str], bool]).
    """

    def validator(text: str) -> bool:
        number = safe_float(text)
        if number is None:
            return False
        return number >= limit

    return validator


def less(limit: Number) -> Callable[[str], bool]:
    """
    Generates a validator function that checks if a number (string input)
    is strictly less than the limit (< limit).

    :param limit: The number to compare against (exclusive).
    :return: A validator function (Callable[[str], bool]).
    """

    def validator(text: str) -> bool:
        number = safe_float(text)
        if number is None:
            return False
        return number < limit

    return validator


def less_or_equal(limit: Number) -> Callable[[str], bool]:
    """
    Generates a validator function that checks if a number (string input)
    is less than or equal to the limit (<= limit).

    :param limit: The number to compare against (inclusive).
    :return: A validator function (Callable[[str], bool]).
    """

    def validator(text: str) -> bool:
        number = safe_float(text)
        if number is None:
            return False
        return number <= limit

    return validator
