'''Provides types used in Nawah'''

from typing import (TYPE_CHECKING, Any, Literal, MutableMapping,
                    MutableSequence, TypedDict, Union)

from nawah.enums import Event

if TYPE_CHECKING:
    from datetime import datetime

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

    from nawah.classes import Package


class Results(TypedDict):
    '''Provides type-hint for return of Nawah Function'''

    status: int
    msg: str
    args: 'ResultsArgs'


ResultsArgs = MutableMapping[str, Any]


class AppPackage(TypedDict):
    '''Provides type-hint for item of 'Config.packages' '''

    package: 'Package'
    modules: MutableSequence[str]


class AnalyticsEvents(TypedDict):
    '''Provides type-hint for 'analytics_events' App Config Attr'''

    app_conn_verified: bool
    session_conn_auth: bool
    session_user_auth: bool
    session_conn_reauth: bool
    session_user_reauth: bool
    session_conn_deauth: bool
    session_user_deauth: bool


class IPQuota(TypedDict):
    '''Provides type-hint for dict used to track IP user quota'''

    counter: int
    last_check: 'datetime'


NawahEvents = MutableSequence[Event]


class NawahEnv(TypedDict, total=False):
    '''Provides type-hint for 'Env' dict'''

    id: str
    init: bool
    conn: 'AsyncIOMotorClient'
    REMOTE_ADDR: str
    HTTP_USER_AGENT: str
    HTTP_ORIGIN: str
    client_app: str
    session: 'NawahSession'
    prev_session: MutableMapping
    prev_session_timeout: 'datetime'
    last_call: 'datetime'
    ws: 'WebSocketResponse'
    quota: 'NawahEnvQuota'
    args: MutableMapping[str, Any]


class NawahEnvQuota(TypedDict):
    '''Provides type-hint for 'quota' of 'Env' dict'''

    counter: int
    last_check: 'datetime'


class NawahSession(TypedDict):
    '''Provieds type-hint for 'session' of 'Env' dict'''

    _id: str
    user: MutableMapping
    groups: MutableSequence[str]
    host_add: str
    user_agent: str
    expiry: str
    token_hash: str
    create_time: str


class NawahQuerySpecialGroup(TypedDict):
    '''Provides type-hint for '$group' in 'NawahQuery' '''

    by: str
    count: int


class NawahQuerySpecialGeoNear(TypedDict):
    '''Provides type-hint for '$geo_near' in 'NawahQuery' '''

    val: str
    attr: str
    dist: int


# Following TypedDict type can't be defined as class as keys include $
NawahQuerySpecial = TypedDict(
    'NawahQuerySpecial',
    {
        '$search': str,
        '$sort': MutableMapping[str, Literal[1, -1]],
        '$skip': int,
        '$limit': int,
        '$extn': Union[bool, MutableSequence[str]],
        '$attrs': MutableSequence[str],
        '$group': MutableSequence[NawahQuerySpecialGroup],
        '$geo_near': NawahQuerySpecialGeoNear,
    },
    total=False,
)

NawahQueryOperEq = TypedDict('NawahQueryOperEq', {'$eq': Any})
NawahQueryOperNe = TypedDict('NawahQueryOperNe', {'$ne': Any})
NawahQueryOperGt = TypedDict('NawahQueryOperGt', {'$gt': Union[int, float, str]})
NawahQueryOperGte = TypedDict('NawahQueryOperGte', {'$gte': Union[int, float, str]})
NawahQueryOperLt = TypedDict('NawahQueryOperLt', {'$lt': Union[int, float, str]})
NawahQueryOperLte = TypedDict('NawahQueryOperLte', {'$lte': Union[int, float, str]})
NawahQueryOperAll = TypedDict('NawahQueryOperAll', {'$all': list[Any]})
NawahQueryOperIn = TypedDict('NawahQueryOperIn', {'$in': list[Any]})
NawahQueryOperNin = TypedDict('NawahQueryOperNin', {'$nin': list[Any]})
NawahQueryOperRegex = TypedDict('NawahQueryOperRegex', {'$regex': str})
NawahQueryStep = dict[
    str,
    Union[
        NawahQueryOperEq,
        NawahQueryOperNe,
        NawahQueryOperGt,
        NawahQueryOperGte,
        NawahQueryOperLt,
        NawahQueryOperLte,
        NawahQueryOperAll,
        NawahQueryOperIn,
        NawahQueryOperNin,
        NawahQueryOperRegex,
    ],
]

NawahQueryOperOr = TypedDict('NawahQueryOperOr', {'$or': list[NawahQueryStep]})
NawahQueryOperAnd = TypedDict('NawahQueryOperAnd', {'$and': list[NawahQueryStep]})

NawahQueryIndex = TypedDict(
    'NawahQueryIndex', {'$index': dict[str, list[tuple[str, Any]]]}
)

NawahDoc = MutableMapping[str, Any]
