from typing import (
    Any,
    Callable,
    Iterable,
    List,
    Sequence,
    Tuple,
    Type,
    TypeVar,
    Union,
    Generic,
)

T = TypeVar('T')
U = TypeVar('U')
TList = TypeVar('TList', bound=List[Any])
TType = TypeVar('TType', bound=Type)
TTypeAny = TypeVar('TTypeAny', bound=Type[Any])
TCallable = TypeVar('TCallable', bound=Callable[..., Any])

untyped_list_str = ['abc', 'def']
typed_list_str: List[str] = ['abc', 'def']

untyped_tuple_str = ('abc',)
typed_tuple_str: Tuple[str] = ('abc',)

untyped_tuple_str_int = ('abc', 4)
typed_tuple_str_int: Tuple[str, int] = ('abc', 4)

variadic_tuple_str: Tuple[str, ...] = ('abc',)
variadic_tuple_str_int: Tuple[Union[str, int], ...] = ('abc', 4)


def untyped_passthrough(x):
    return x

def typed_list_generic_passthrough(x: List[T]) -> List[T]:
    return x

def typed_tuple_generic_passthrough(x: Tuple[T]) -> Tuple[T]:
    return x

def typed_multi_typed_tuple_generic_passthrough(x: Tuple[T, U]) -> Tuple[U, T]:
    return x[1], x[0]

def typed_variadic_tuple_generic_passthrough(x: Tuple[T, ...]) -> Sequence[T]:
    return x

def typed_iterable_generic_passthrough(x: Iterable[T]) -> Iterable[T]:
    return x

def typed_fully_generic_passthrough(x: T) -> T:
    return x

def typed_bound_generic_passthrough(x: TList) -> TList:
    #? list()
    x

    return x

# Forward references are more likely with custom types, however this aims to
# test just the handling of the quoted type rather than any other part of the
# machinery.
def typed_quoted_return_generic_passthrough(x: T) -> 'List[T]':
    return [x]

def typed_quoted_input_generic_passthrough(x: 'Tuple[T]') -> T:
    x
    return x[0]


for a in untyped_passthrough(untyped_list_str):
    #? str()
    a

for b in untyped_passthrough(typed_list_str):
    #? str()
    b


for c in typed_list_generic_passthrough(untyped_list_str):
    #? str()
    c

for d in typed_list_generic_passthrough(typed_list_str):
    #? str()
    d


for e in typed_iterable_generic_passthrough(untyped_list_str):
    #? str()
    e

for f in typed_iterable_generic_passthrough(typed_list_str):
    #? str()
    f


for g in typed_tuple_generic_passthrough(untyped_tuple_str):
    #? str()
    g

for h in typed_tuple_generic_passthrough(typed_tuple_str):
    #? str()
    h


out_untyped = typed_multi_typed_tuple_generic_passthrough(untyped_tuple_str_int)
#? int()
out_untyped[0]
#? str()
out_untyped[1]


out_typed = typed_multi_typed_tuple_generic_passthrough(typed_tuple_str_int)
#? int()
out_typed[0]
#? str()
out_typed[1]


for j in typed_variadic_tuple_generic_passthrough(untyped_tuple_str_int):
    #? str() int()
    j

for k in typed_variadic_tuple_generic_passthrough(typed_tuple_str_int):
    #? str() int()
    k

for l in typed_variadic_tuple_generic_passthrough(variadic_tuple_str):
    #? str()
    l

for m in typed_variadic_tuple_generic_passthrough(variadic_tuple_str_int):
    #? str() int()
    m

#? float
typed_fully_generic_passthrough(float)

for n in typed_fully_generic_passthrough(untyped_list_str):
    #? str()
    n

for o in typed_fully_generic_passthrough(typed_list_str):
    #? str()
    o


for p in typed_bound_generic_passthrough(untyped_list_str):
    #? str()
    p

for q in typed_bound_generic_passthrough(typed_list_str):
    #? str()
    q


for r in typed_quoted_return_generic_passthrough("something"):
    #? str()
    r

for s in typed_quoted_return_generic_passthrough(42):
    #? int()
    s


#? str()
typed_quoted_input_generic_passthrough(("something",))

#? int()
typed_quoted_input_generic_passthrough((42,))



class CustomList(List):
    def get_first(self):
        return self[0]


#? str()
CustomList[str]()[0]
#? str()
CustomList[str]().get_first()

#? str()
typed_fully_generic_passthrough(CustomList[str]())[0]
#?
typed_list_generic_passthrough(CustomList[str])[0]


def typed_bound_type_implicit_any_generic_passthrough(x: TType) -> TType:
    #? Type()
    x
    return x

def typed_bound_type_any_generic_passthrough(x: TTypeAny) -> TTypeAny:
    # Should be Type(), though we don't get the handling of the nested argument
    # to `Type[...]` quite right here.
    x
    return x


class MyClass:
    pass

def my_func(a: str, b: int) -> float:
    pass

#? MyClass
typed_fully_generic_passthrough(MyClass)

#? MyClass()
typed_fully_generic_passthrough(MyClass())

#? my_func
typed_fully_generic_passthrough(my_func)

#? CustomList()
typed_bound_generic_passthrough(CustomList[str]())

# should be list(), but we don't validate generic typevar upper bounds
#? int()
typed_bound_generic_passthrough(42)

#? MyClass
typed_bound_type_implicit_any_generic_passthrough(MyClass)

#? MyClass
typed_bound_type_any_generic_passthrough(MyClass)

# should be Type(), but we don't validate generic typevar upper bounds
#? int()
typed_bound_type_implicit_any_generic_passthrough(42)

# should be Type(), but we don't validate generic typevar upper bounds
#? int()
typed_bound_type_any_generic_passthrough(42)


def decorator(fn: TCallable) -> TCallable:
    pass


def will_be_decorated(the_param: complex) -> float:
    pass


is_decorated = decorator(will_be_decorated)

#? will_be_decorated
is_decorated

#? ['the_param=']
is_decorated(the_para
)


class class_decorator_factory_plain:
    def __call__(self, func: T) -> T:
        ...

#? class_decorator_factory_plain()
class_decorator_factory_plain()

#?
class_decorator_factory_plain()()

is_decorated_by_class_decorator_factory = class_decorator_factory_plain()(will_be_decorated)

#? will_be_decorated
is_decorated_by_class_decorator_factory

#? ['the_param=']
is_decorated_by_class_decorator_factory(the_par
)


def decorator_factory_plain() -> Callable[[T], T]:
    pass

#? Callable()
decorator_factory_plain()

#?
decorator_factory_plain()()

#? int()
decorator_factory_plain()(42)

is_decorated_by_plain_factory = decorator_factory_plain()(will_be_decorated)

#? will_be_decorated
is_decorated_by_plain_factory

#? ['the_param=']
is_decorated_by_plain_factory(the_par
)


class class_decorator_factory_bound_callable:
    def __call__(self, func: TCallable) -> TCallable:
        ...

#? class_decorator_factory_bound_callable()
class_decorator_factory_bound_callable()

#? Callable()
class_decorator_factory_bound_callable()()

is_decorated_by_class_bound_factory = class_decorator_factory_bound_callable()(will_be_decorated)

#? will_be_decorated
is_decorated_by_class_bound_factory

#? ['the_param=']
is_decorated_by_class_bound_factory(the_par
)


def decorator_factory_bound_callable() -> Callable[[TCallable], TCallable]:
    pass

#? Callable()
decorator_factory_bound_callable()

#? Callable()
decorator_factory_bound_callable()()

is_decorated_by_bound_factory = decorator_factory_bound_callable()(will_be_decorated)

#? will_be_decorated
is_decorated_by_bound_factory

#? ['the_param=']
is_decorated_by_bound_factory(the_par
)


class That(Generic[T]):
    def __init__(self, items: List[Tuple[str, T]]) -> None:
        pass

    def get(self) -> T:
        pass

inst = That([("abc", 2)])

# No completions here, but should have completions for `int`
#? int()
inst.get()
