from enum import Enum, auto as enum_auto
from typing import Any, ParamSpec, TypeVar
from collections.abc import Callable, Sequence


P = ParamSpec('P')
T = TypeVar('T')


JSON = int | str | bool | list['JSON'] | dict[str, 'JSON'] | None
F_DECORATOR = Callable[[Callable[P, T]], Callable[P, T]]


class AutoNameEnum(Enum):
    @staticmethod
    def _generate_next_value_(name, start, count, last_values):
        return name


class EmptyStr(str, Enum):
    EMPTY_STR = ''


class HTTPMethod(str, AutoNameEnum):
    DELETE = enum_auto()
    PATCH = enum_auto()
    PUT = enum_auto()
    POST = enum_auto()
    GET = enum_auto()


def gen_cls_name_from_url_path(url_path: str, postfix: str = ''):
    parts = url_path.strip('/').replace('-', '').replace('_', '/').split('/')
    base = ''.join(f'{p[0].upper()}{p[1:]}' for p in parts)
    return f'{base}{postfix}'


def get_nested_value(
    d: dict,
    keys: Sequence[str],
    default: Any = None,
    raise_if_value_is_none: bool = False,
) -> Any:
    if not isinstance(d, dict):
        raise TypeError

    if not keys:
        raise ValueError

    key = keys[0]
    if key not in d:
        return default
    value = d[key]

    if len(keys) > 1:
        if isinstance(value, dict):
            nested_d = value
            return get_nested_value(
                d=nested_d,
                keys=keys[1:],
                default=default,
            )

        if not raise_if_value_is_none and value is None:
            return default

        raise TypeError(
            f'The key {key} found, but its value is not a dictionary.'
        )
    return value
