from __future__ import annotations

import copy
from typing import Any
from typing import overload
from typing import TypeVar

import numpy as np
from typing_extensions import TypeGuard


T_str = TypeVar('T_str', bound=str)


@overload
def to_list(key: None) -> list[Any]: ...


@overload
def to_list(key: list[T_str]) -> list[T_str]: ...


@overload
def to_list(key: tuple[T_str]) -> list[T_str]: ...


@overload
def to_list(key: T_str) -> list[T_str]: ...


def to_list(key: T_str | list[T_str] | tuple[T_str] | None) -> list[T_str] | list[Any]:
    if key is None:
        return []
    elif isinstance(key, list):
        return copy.copy(key)
    elif isinstance(key, tuple):
        return [*key]
    else:
        return [key]


def is_int(x: Any) -> TypeGuard[int]:
    return np.issubdtype(type(x), np.integer)


def is_num(x: Any) -> TypeGuard[int | float]:
    # See: https://stackoverflow.com/a/37727662
    return np.issubdtype(type(x), np.number)
