from typing import Union
import ast
from typing import List


def check_function(
    function: Union[ast.FunctionDef, ast.AsyncFunctionDef], inside_class: bool
) -> List[str]:
    """
    Check a single function for type annotations and return a list of strings of issues
    """
    function_issues = []
    function_name = f"{function.name}:{function.lineno}"

    has_classmethod = any(
        isinstance(decorator, ast.Name)
        and decorator.id == "classmethod"
        and isinstance(decorator.ctx, ast.Load)
        for decorator in function.decorator_list
    )

    has_property = any(
        isinstance(decorator, ast.Name)
        and decorator.id == "property"
        and isinstance(decorator.ctx, ast.Load)
        for decorator in function.decorator_list
    )

    for i, arg in enumerate(function.args.args):
        # if the function is inside a class, and is a class method
        if inside_class and i == 0 and arg.arg == "cls" and has_classmethod:
            continue

        # if the function is inside a class, and is a property
        if inside_class and i == 0 and arg.arg == "cls" and has_property:
            continue

        # if the function is the __new__ method
        if inside_class and i == 0 and arg.arg == "cls" and function.name == "__new__":
            continue

        # if the function is inside a class, and is a normal method
        if inside_class and i == 0 and arg.arg == "self":
            continue

        # static methods have no special treatment

        # check positional arguments for type annotations
        if arg.annotation is None:
            function_issues.append(
                f"Argument '{arg.arg}' of function '{function_name}' has no type annotation"
            )

    # check keyword arguments for type annotations
    for arg in function.args.kwonlyargs:
        if arg.annotation is None:
            function_issues.append(
                f"Argument '{arg.arg}' of function '{function_name}' has no type annotation"
            )

    # check that function has a return type annotation
    # __init__ and __new__ functions are allowed to have no return type annotation
    if function.returns is None and function.name not in ["__init__", "__new__"]:
        function_issues.append(
            f"Function '{function_name}' has no return type annotation"
        )

    return function_issues