from .method import (
    banChatMember,
    deleteChatKeypad,
    deleteMessage,
    editChatKeypad,
    editMessageKeypad,
    editMessageText,
    forwardMessage,
    getChat,
    getFile,
    getMe,
    getUpdates,
    requestSendFile,
    sendFile,
    sendLocation,
    sendMessage,
    sendPoll,
    setCommand,
    unbanChatMember,
    updateBotEndpoints,
    uploadFile
    )

from . import models

import httpx

class ReplyHolder:
    class Reply:
        def __init__(self, id: str, func):
            self.id = id
            self.send_message = func

        async def __call__(
                self,
                text: str,
                chat_keypad: models.Keypad = None,
                disable_notification: bool = False,
                inline_keypad: models.Keypad = None,
                reply_to_message_id: str = None,
                chat_keypad_type: models.enums.ChatKeypadTypeEnum = None,
        ):
            return await self.send_message(self.id, text, chat_keypad, disable_notification, inline_keypad, reply_to_message_id, chat_keypad_type)

class Methods(
    banChatMember,
    deleteChatKeypad,
    deleteMessage,
    editChatKeypad,
    editMessageKeypad,
    editMessageText,
    forwardMessage,
    getChat,
    getFile,
    getMe,
    getUpdates,
    requestSendFile,
    sendFile,
    sendLocation,
    sendMessage,
    sendPoll,
    setCommand,
    unbanChatMember,
    updateBotEndpoints,
    uploadFile,
    ReplyHolder
    ):

    async def call_method(self, client: httpx.AsyncClient, method: str, data):
        if 'self' in data:
            data.pop('self')
        
        data_ = data.copy()
        for key in data_:
            if data[key] is None:
                data.pop(key)
        
        newData = {}
        for key, value in data.items():

            if value is None:
                continue

            if isinstance(value, (list, tuple, set)):
                newData[key] = [
                    item.to_dict() if hasattr(item, "to_dict") else item.get_() if hasattr(item, 'get_') else item
                    for item in value
                ]

            elif hasattr(value, "to_dict"):
                newData[key] = value.to_dict()

            elif hasattr(value, "get_"):
                newData[key] = value.get_()

            else:
                newData[key] = value

        data = newData

        url = self.BASE_URL.format(self.autH_) + method
        req = await client.post(url, json=(((data) or None)))
        res = req.json()
        if req.status_code != 200:
            raise Exception("Connection error: {}".format(req.text))
        if res['status'] != "OK":
            raise Exception("Error from rubika, status is not ok: %s" % res["status"])
        return req

    async def set_state(
            self,
            user_id: str,
            state: str
    ):
        async with self.states_lock:
            self.states[user_id] = state
    
    async def del_state(
            self,
            user_id: str
    ):
        async with self.states_lock:
            self.states.pop(user_id)
    
    async def get_state(
            self,
            user_id: str
    ):
        async with self.states_lock:
            return self.states.get(user_id)