from .kavk_api import Vk
from .types import bot_events as BotEvents


class BotLongPoll:
    def __init__(self, vk:Vk, wait:int=25) -> None:
        '''
        Класс для работы с BotLongPoll

        ...
        
        vk:Vk
            Объект kavk_api.Vk
        wait:int = 25
            Время ожидания
        '''
        self._vk = vk
        self._wait = wait
        self._server = ''
        self._params = {}
        self._updates = []

    async def listen(self):
        '''Генератор ивентов BotLongPoll'''
        while 1:
            async for event in BotLongPoll(self._vk, self._wait):
                yield event

    async def update_params(self) -> None:
        '''Обновление self._params и self._server'''
        group_id = await self._vk.groups.getById()
        self.group_id = group_id[0].id
        r = await self._vk.groups.getLongPollServer(group_id=self.group_id)
        self._params:dict = {'key': r.key, 'ts': r.ts, 'wait': self._wait}
        self._server:str = r.server

    
    async def get_event(self) -> list:
        '''Получение списка сырых ивентов'''
        if self._params == {}:
            await self.update_params()
        r = await self._vk.client.get(url=self._server, params=self._params)
        r = await r.json()
        self._params.update({'ts': r['ts']})
        try:
            updates:list = r['updates']
        except IndexError:
            error = r['failed']
            if error == 1:
                self._params.update({'ts': r['ts']})
            elif error == 2 or error == 3:
                self._params = {}
            updates = []
        except Exception as e:
            raise e

        return updates

    # Что происходит дальше?
    # __aiter__ возвращает коду `async for e in LongPoll.listen()`
    # функцию __anext__.
    # Она же в свою очередь просто получает наш новый ивент и обрабатывает его

    def __aiter__(self): return self

    async def __anext__(self):
        if self._updates != []:
            u:dict = self._updates.pop(0)
            event = BotEvents._get_event(u.get('type',''))
            return event(**u, raw=u)
            
        updates = []
        while updates == []:
            '''
            Если событий за время self._wait не произойдёт, мы получим в ответ пустой список.
            Т.к. делать ивент из такого ответа хз как, мы просто ждем когда прийдет нормальный
            '''
            updates = await self.get_event() 
        
        if len(updates) > 0:
            self._updates = updates[1:]
            update:dict = updates[0]
        else: update:dict = updates[0]
        event_type = str(update.get('type', ''))
        event = BotEvents._get_event(event_type)
        return event(**update, raw=update)

__all__ = ("BotLongPoll", 'BotEvents')
