import datetime
from asyncio import Task
from typing import (TYPE_CHECKING, Any, AsyncGenerator, Callable, Coroutine,
                    Dict, List, Literal, Optional, TypedDict, Union)

from aiohttp.web import WebSocketResponse
from motor.motor_asyncio import AsyncIOMotorClient

from nawah.enums import Event

NAWAH_EVENTS = List[Event]

WATCH_TASK = TypedDict(
    'WATCH_TASK',
    {
        'watch': Coroutine[Any, Any, None],
        'task': Task,
        'stream': Any,
    },
    total=False,
)

NAWAH_ENV_QUOTA = TypedDict(
    'NAWAH_ENV_QUOTA',
    {
        'counter': int,
        'last_check': datetime.datetime,
    },
)

NAWAH_ENV = TypedDict(
    'NAWAH_ENV',
    {
        'id': int,
        'init': bool,
        'conn': AsyncIOMotorClient,
        'REMOTE_ADDR': str,
        'HTTP_USER_AGENT': str,
        'HTTP_ORIGIN': str,
        'client_app': str,
        'session': Dict,
        'last_call': datetime.datetime,
        'ws': WebSocketResponse,
        'watch_tasks': Dict[str, WATCH_TASK],
        'quota': NAWAH_ENV_QUOTA,
    },
    total=False,
)

NAWAH_QUERY_SPECIAL_GROUP = TypedDict(
    'NAWAH_QUERY_SPECIAL_GROUP', {'by': str, 'count': int}
)

NAWAH_QUERY_SPECIAL_GEO_NEAR = TypedDict(
    'NAWAH_QUERY_SPECIAL_GEO_NEAR', {'val': str, 'attr': str, 'dist': int}
)

NAWAH_QUERY_SPECIAL = TypedDict(
    'NAWAH_QUERY_SPECIAL',
    {
        '$search': Optional[str],
        '$sort': Optional[Dict[str, Literal[1, -1]]],
        '$skip': Optional[int],
        '$limit': Optional[int],
        '$extn': Optional[Union[Literal[False], List[str]]],
        '$attrs': Optional[List[str]],
        '$group': Optional[List[NAWAH_QUERY_SPECIAL_GEO_NEAR]],
        '$geo_near': Optional[NAWAH_QUERY_SPECIAL_GEO_NEAR],
    },
    total=False,
)

NAWAH_QUERY = List[  # type: ignore
    Union[
        'NAWAH_QUERY',  # type: ignore
        Union[
            Dict[
                str,
                Union[
                    'NAWAH_QUERY',  # type: ignore
                    Any,
                    Union[
                        Dict[Literal['$eq'], Any],
                        Dict[Literal['$ne'], Any],
                        Dict[Literal['$gt'], Union[int, str]],
                        Dict[Literal['$gte'], Union[int, str]],
                        Dict[Literal['$lt'], Union[int, str]],
                        Dict[Literal['$lte'], Union[int, str]],
                        Dict[Literal['$bet'], Union[List[int], List[str]]],
                        Dict[Literal['$all'], List[Any]],
                        Dict[Literal['$in'], List[Any]],
                        Dict[Literal['$nin'], List[Any]],
                        Dict[Literal['$regex'], str],
                    ],
                ],
            ],
            NAWAH_QUERY_SPECIAL,
        ],
    ]
]

NAWAH_DOC = Dict[
    str,
    Union[
        Dict[
            str,
            Union[
                Dict[Literal['$add'], int],
                Dict[Literal['$multiply'], int],
                Dict[Literal['$append'], Any],
                Dict[Literal['$set_index'], Dict[int, Any]],
                Dict[Literal['$set_index'], Dict[int, Any]],
                Dict[Literal['$del_val'], Any],
                Dict[Literal['$del_index'], int],
                Any,
            ],
        ],
        Any,
    ],
]

IP_QUOTA = TypedDict(
    'IP_QUOTA',
    {
        'counter': int,
        'last_check': datetime.datetime,
    },
)
