from .core import AsyncSnooper, AsyncSnoopContext
from typing import Optional, Union, TextIO, Callable


def async_snoop(
    output: Optional[Union[str, TextIO, Callable[[str], None]]] = None,
    depth: int = 1,
    watch: tuple = (),
    watch_explode: tuple = (),
    prefix: str = "",
    overwrite: bool = False,
    thread_info: bool = False,
    color: bool = True,
):
    """
    Create an async tracer wrapper

    Args:
        output:
            - None: to stderr
            - str: to str filename
            - TextIO: to str file obj
            - Callable: to str/callable function
        depth: Trace depth
            1: Only trace the decorated function (default)
            2: Trace the function and its direct calls
            N: Trace up to N levels deep
        watch: Tuple of expressions to monitor
            Example: ('x.y', 'self.data[0]', 'len(items)')
        watch_explode: Variables to expand and watch
            Example: ('self.config', 'data_dict')
        prefix: Prefix added at the beginning of each output line
        overwrite: Whether to overwrite the output file (default is to append)
        thread_info: Whether to include thread information
        color: Whether to use colors (terminal only)

    Returns:
        A wrapper obj

    Examples:
        @async_snoop()
        async def my_func():
            pass

        @async_snoop(output='debug.log', watch=('user.id',))
        async def process_user(user):
            pass
    """
    return AsyncSnooper(
        output=output,
        depth=depth,
        watch=watch,
        watch_explode=watch_explode,
        prefix=prefix,
        overwrite=overwrite,
        thread_info=thread_info,
        color=color,
    )


def async_snoop_context(
    output: Optional[Union[str, TextIO, Callable[[str], None]]] = None,
    depth: int = 1,
    watch: tuple = (),
    watch_explode: tuple = (),
    prefix: str = "",
    overwrite: bool = False,
    thread_info: bool = False,
    color: bool = True,
):
    """
    Create a context manager for async snoop.
    Is will debug in a part of func.

    Examples:
        async with async_snoop_context():
            await some_async_operation()
            x = compute()

        async with async_snoop_context(output='block.log', watch=('x',)):
            await process_data(x)
    """
    return AsyncSnoopContext(
        output=output,
        depth=depth,
        watch=watch,
        watch_explode=watch_explode,
        prefix=prefix,
        overwrite=overwrite,
        thread_info=thread_info,
        color=color,
    )
