from collections.abc import Callable
from random import choice, choices, randint, random
from string import ascii_letters, ascii_lowercase, ascii_uppercase
from typing import Literal


def pascalcase(
        subwords: int | None = None,
        max_length: int | None = None,
        sub_length_min: int = 3,
        sub_length_max: int = 6,
    ) -> str:
        if not max_length:
            max_length = randint(5, 12)
        if not subwords:
            subwords = int(max_length / sub_length_min) + 1
        return "".join(
            titlecase(randint(sub_length_min, sub_length_max)) for _ in range(subwords)
        )[:max_length]

def camelcase(
        subwords: int | None = None,
        max_length: int | None = None,
        sub_length_min: int = 3,
        sub_length_max: int = 6,
    ) -> str:
        if not max_length:
            max_length = randint(5, 12)
        if not subwords:
            subwords = int(max_length / sub_length_min) + 1
        return "".join(
            (
                lowercase(randint(sub_length_min, sub_length_max)),
                *(titlecase(randint(sub_length_min, sub_length_max)) for _ in range(subwords)),
            )
        )[:max_length]

def snakecase(
        subwords: int | None = None,
        max_length: int | None = None,
        sub_length_min: int = 3,
        sub_length_max: int = 6,
    ) -> str:
        if not max_length:
            max_length = randint(5, 12)
        if not subwords:
            subwords = int(max_length / sub_length_min) + 1
        return "_".join(
            lowercase(randint(sub_length_min, sub_length_max)) for _ in range(subwords)
        )[:max_length]

def kebabcase(
        subwords: int | None = None,
        max_length: int | None = None,
        sub_length_min: int = 3,
        sub_length_max: int = 6,
    ) -> str:
        if not max_length:
            max_length = randint(5, 12)
        if not subwords:
            subwords = int(max_length / sub_length_min) + 1
        return "-".join(
            lowercase(randint(sub_length_min, sub_length_max)) for _ in range(subwords)
        )[:max_length]

def string_tuple(
        string_type: Literal["any", "lower", "upper", "camel", "pascal"] = "any",
        length: int | None = None,
        string_length: int | None = None,
    ) -> tuple[str, ...]:
        stringmaker: Callable[[int | None], str]
        stringmakers: dict[str, Callable[[int | None], str]] = {
            "any": string,
            "lower": lowercase,
            "upper": uppercase,
            "camel": camelcase,
            "pascal": pascalcase,
            "snake": snakecase,
            "kebab": kebabcase,
        }
        stringmaker = stringmakers[string_type]

        if not length:
            length = randint(2, 9)
        return tuple(stringmaker(string_length) for i in range(length))

def text(num_words: int = 10, min_word_length: int = 3, max_word_length: int = 10) -> str:
        return " ".join(
            string(length=randint(min_word_length, max_word_length)) for _ in range(num_words)
        )

def string(length: int | None = None) -> str:
        if not length:
            length = randint(2, 9)
        return "".join(choices(ascii_letters, k=length))

def lowercase(length: int | None = None) -> str:
        if not length:
            length = randint(2, 9)
        return "".join(choices(ascii_lowercase, k=length))

def titlecase(length: int | None = None) -> str:
        if not length:
            length = randint(2, 9)
        return choice(ascii_uppercase) + "".join(choices(ascii_lowercase, k=length - 1))

def uppercase(length: int | None = None) -> str:
        if not length:
            length = randint(2, 9)
        return "".join(choices(ascii_uppercase, k=length))

def int_tuple(
        size: int | None = None,
        min_val: int = 0,
        max_val: int = 20,
    ) -> tuple[int, ...]:
        if size is None:
            size = randint(2, 10)
        return tuple(randint(min_val, max_val) for _ in range(size))

def randfloat(lower: float = 0.0, upper: float = 1.0) -> float:
        return lower + random() * (upper - lower)


if __name__ == "__main__":
    print(".string():       ", string())
    print(".lowercase():    ", lowercase())
    print(".titlecase():    ", titlecase())
    print(".uppercase():    ", uppercase())
    print(".pascalcase():   ", pascalcase())
    print(".camelcase():    ", camelcase())
    print(".snakecase():    ", snakecase())
    print(".kebabcase():    ", kebabcase())
    print(".string_tuple():  ", string_tuple())
    print(".int_tuple():    ", int_tuple())
    print(".randfloat():    ", randfloat())
    print()
    print(".string():       ", string())
    print(".lowercase():    ", lowercase())
    print(".titlecase():    ", titlecase())
    print(".uppercase():    ", uppercase())
    print(".pascalcase():   ", pascalcase())
    print(".camelcase():    ", camelcase())
    print(".snakecase():    ", snakecase())
    print(".kebabcase():    ", kebabcase())
    print(".string_tuple():  ", string_tuple("pascal"))
    print(".int_tuple():    ", int_tuple(size=20, min_val=50, max_val=60))
    print(".randfloat():    ", randfloat(6.0, 7.0))
