#!/bin/python

from os import path

if __name__ == '__main__' and  __package__ == None or __package__ == '':
    import sys
    sys.path.append(path.join(path.dirname(__file__), '..'))

import logging
import platform
import typing
import webbrowser
from base64 import b64encode, urlsafe_b64decode
from datetime import datetime
from json import dumps, loads
from os import system
from pathlib import Path
from random import choice, randint, sample
from re import compile as com
from re import findall, search, sub
from time import sleep
from warnings import warn

from Crypto.Cipher.AES import MODE_CBC, block_size, new
from Crypto.Util.Padding import pad, unpad
from python_rubika import __name__ as base
from requests import get, post, session


class UpToDate(object):

    @classmethod
    def __init__(cls,
                 version: str, url: str) -> ...:
        cls._ver, cls._url = version, url
    
    def up(cls) -> (str):
        if str(get(cls._url).text) != cls._ver:
            return 'notUpdated'
        else:
            return 'isUpdated'
    
    def user(cls) -> (up):

        if cls.up() != 'isUpdated':
            if input('new version rubx now up to date? y/n : ').upper() == 'Y':
                system('pip install rubx --upgrade')
                if platform.system() == 'Windows':
                    system('cls')
                else:
                    system('clear')
        else:
            ... # is full version

class Clean(str):
    
    @staticmethod
    def html_cleaner(text: str) -> (str):
        return sub(
            com(
                r'<.*?>|&([a-z0-9]+|#[0-9]{1,6}|#x[0-9a-f]{1,6});'
                ),
            '',
            text
            )

class Scanner(
    object
    ):
    
    @staticmethod
    def check_type(
        chat_id: str
        ) -> (
            str
            or
            ...
            ):
             
            if len(chat_id) > 2:
                
                if   chat_id[:2].lower() == 'g0':
                    return 'Group'
                elif chat_id[:2].lower() == 'c0':
                    return 'Channel'
                elif chat_id[:2].lower() == 'u0':
                    return 'User'
                elif chat_id[:2].lower() == 's0':
                    return 'Service'
                elif chat_id[:2].lower() == 'b0':
                    return 'Bot'
                else                            :
                    raise ValueError(f'CHAT ID \'{chat_id}\' NOT FOUND!')
            
            else:
                raise ValueError(f'CHAT ID \'{chat_id}\' FALSE!')

class Maker(
    object
    ):

    @staticmethod
    def check_link(link: str, key: str) -> (str):
        with Client(key, banner=False) as client:
            
            if link.startswith('@') or search(r'rubika\.ir/\w{4,25}'):

                link: str = link.replace('https://', '').replace('rubika.ir/', '')
                result: dict = client.get_object_by_username(link.replace('@', '')).get('data')
                result: dict = result.get('user') or result.get('channel') or result.get('group')
                return result.get('user_guid') or result.get('channel_guid') or result.get('group_guid')
            
            elif len(link) == 56 or len(link) == 48 and 'joing' in link or 'joinc' in link:
                
                if 'joinc' in link:
                    return client.group_preview_by_join_link(link)['data']['group']['group_guid']
                elif 'joing' in link:
                    return client.channel_preview_by_join_link(link)['data']['channel']['channel_guid']

class Login(
    object
    ):

    @staticmethod
    def SignIn(phone: str) -> (str):
        return Client.sign_in(phone, Client.send_code(phone, input('send type is SMS/Interval : '), password=input('please enter your password : ') if input('insert password y/n : ').lower() == 'y' else None).get('data').get('phone_code_hash'), input('please enter activation code : ')).get('data').get('auth') or '0'

class Metas(
    object
    ):
    def checker(
        text: str
        ) -> list:
        result, texts = [], text.replace(
            '**', ''
            ).replace(
                '__', ''
                ).replace(
                    '``',
                    ''
                    ).replace(
                        '__',
                        ''
                        )
        if (
            '**' in text
            ):
            Bold: list = findall(
                r'\*\*(.*?)\*\*',
                text
                )
        boldFromIndex: list = [
            text.index(
                i
                ) for i in Bold
            ]
        [
            (
                result.append(
                    {
                        'from_index'    :   from_index-2,
                        'length'        :   len(length),
                        'type'          :   'Bold'
                        }
                    )
                ) for from_index, length in zip(
                    boldFromIndex,
                    Bold
                    )
                ]
        if (
            '__' in text
            ):
            Italic: list = findall(
                r'\_\_(.*?)\_\_',
                text
                )
        ItalicFromIndex: list = [
            text.index(
                i
                ) for i in Italic
            ]
        [
            (
                result.append(
                    {
                        'from_index'    :   from_index-2,
                        'from_index'    :   len(length),
                        'type'          :   'Italic'
                        }
                    )
                ) for from_index , length in zip(
                    ItalicFromIndex,
                    Italic
                    )
                ]
        if (
            '``' in text
            ):
            Mono: list = findall(
                r'\`\`(.*?)\`\`',
                text
                )
        monoFromIndex: list = [
            text.index(
                i
                ) for i in Mono
            ]
        [
            text.index(
                i
                ) for i in Mono
            ]
        [
            (
                result.append(
                    {
                        'from_index'    :   from_index-2,
                        'length'        :   len(length),
                        'type'          :   'Mono'
                        }
                    )
                ) for from_index , length in zip(
                    monoFromIndex,
                    Mono
                    )
                ]
        return [
            result,
            texts
            ]

class Tags(
    object
    ):
    def checker(
        text: str,
        guids=None,
        types=None) -> list:
        (
            result,
            texts
            ) = [], text.replace(
            '@',
            ''
            )
        Tags: list = findall(
            r'\@(.*?)\@',
            text
            )
        tagFromIndex: list = [
            text.index(
                i
                ) for i in Tags
            ]
        [
            (
                result.append(
                    {
                        'type'                      :   'MentionText',
                        'mention_text_object_guid'  :   guid,
                        'from_index'                :   from_index-1,
                        'length'                    :   len(
                            length
                            ),
                        'mention_text_object_type': mode
                        }
                    )
                )
            for from_index,
            length,
            guid,
            mode in zip(
                tagFromIndex,
                Tags,
                guids,
                types
                )
            ]
        return [
            result,
            texts
            ]

class Device(dict):
    defaultDevice: dict = {
        'app_version'           :   'MA_2.9.8',
        'device_hash'           :   'CEF34215E3E610825DC1C4BF9864D47A',
        'device_model'          :   'rubx-lib',
        'is_multi_account'      :   False,
        'lang_code'             :   'fa',
        'system_version'        :   'SDK 22',
        'token'                 :   'cgpzI3mbTPKddhgKQV9lwS:APA91bE3ZrCdFosZAm5qUaG29xJhCjzw37wE4CdzAwZTawnHZM_hwZYbPPmBedllAHlm60v5N2ms-0OIqJuFd5dWRAqac2Ov-gBzyjMx5FEBJ_7nbBv5z6hl4_XiJ3wRMcVtxCVM9TA-',
        'token_type'            :   'Firebase'
    }

class Infos(str):
    citys, proxys, auth_, sent = [], [], [], (
        lambda data: [
            'error' if data[
                'status'
                ].lower() != 'ok' else 'yeah'
            ]
        )

class Accesses(object):
    
    class Admin(str):
        (
            PinMessages,
            setAdmin,
            ChangeInfo,
            BanMember,
            SetJoinLink,
            SetMemberAccess,
            DeleteGlobalAllMessages
            ) = (
                'PinMessages',
                'setAdmin',
                'ChangeInfo',
                'BanMember',
                'SetJoinLink',
                'SetMemberAccess',
                'DeleteGlobalAllMessages'
                )
    class User(str):
        (
            ViewMembers,
            ViewAdmins,
            SendMessages,
            AddMember
            ) = (
                'ViewMembers',
                'ViewAdmins',
                'SendMessages',
                'AddMember'
                )


class Encryption(
    object
    ):
    
    @classmethod
    
    def __init__(cls, auth_key: str) -> ...:
        if not 32 == len(auth_key) :
            raise IndexError('[SORRY]: len your session key is not \'32\'')
        cls.auth_key, cls.iv = bytearray((''.join(list(map(lambda a: chr((a - ord('a') + 9) % 26 + ord('a')), (str(auth_key[16:24] + auth_key[:8] + auth_key[24:32] + auth_key[8:16]).encode('latin-1')))))), 'utf-8'), bytearray.fromhex(str('0' * len(auth_key)))

    def encrypt(cls, data: str) -> (str):
        return (b64encode(new(cls.auth_key, MODE_CBC, iv=cls.iv).encrypt(pad(data.encode('utf-8'), block_size))).decode('utf-8'))

    def decrypt(cls, data: str) -> (str):
        return (unpad(new(cls.auth_key, MODE_CBC, iv=cls.iv).decrypt(urlsafe_b64decode(data.encode('utf-8'))), block_size)).decode('utf-8')

#!/bin/python

class MainError(Exception):
    pass

class NotREGISTERED(IOError):
    ...

class InvalidInput(IOError):
    ...

class TooREQUESTS(IOError):
    ...

class InvalidAUTH(IOError):
    ...

class ConnectError(BaseException):
    ...

class ClientError(Exception):
    ...

class ServerError(
    Exception
    ):
    ...

class Errors(
    Exception
    ):
    
    def MadeError(status: str, det: str) -> (bool or ...):

        if status.upper() == 'ERROR_GENERIC' or status.upper() == 'ERROR_ACTION':
            if 'NOT_REGISTERED' in det.upper():
                raise NotREGISTERED('session key not found; please find your key in web.rubika.ir and try again.')
            elif 'INVALID_INPUT' in det.upper():
                raise InvalidInput('your inserts is not true; try again.')
            elif 'TOO_REQUESTS' in det.upper():
                raise TooREQUESTS('sorry; method has been limited, please try again later.')
            elif 'INVALID_AUTH' in det.upper():
                raise InvalidAUTH('sorry; server error or please check method arguments and try again.')
            else:
                return True
        else:
            return True

class ClientConnectorError(object):
    
    @classmethod
    def __init__(cls, **kwargs: object) -> (...):
        cls.set_error: ConnectError = kwargs.get('error')
        cls.name: str = kwargs.get('name')
        super().__init__(cls.name, cls.set_error)
        
    @property
    def raises(cls) -> (Exception):
        raise cls.set_error(f'this error for {cls.name}')
    
    @property
    def returns(cls) -> (str):
        return 'this error for %s please fixed and try again.' %  cls.name

#!/bin/python

import sqlite3

suffix: str = '.rbs'
rbs_version: int = 1

class SQLiteSession(object):

    def __init__(self, session: str) -> ...:
        self.filename = session
        if not session.endswith(suffix):
            self.filename += suffix

        self._connection = sqlite3.connect(self.filename,
                                           check_same_thread=False)
        cursor = self._connection.cursor()
        cursor.execute('select name from sqlite_master '
                       'where type=? and name=?', ('table', 'version'))
        if cursor.fetchone():
            cursor.execute('select version from version')
            version = cursor.fetchone()[0]
            if rbs_version != version:
                self.upgrade_database(version)

        else:
            cursor.execute(
                'create table version (version integer primary key)')
            cursor.execute('insert into version values (?)', (rbs_version,))
            cursor.execute('create table session (phone text primary key'
                           ', auth text, guid text, agent text)')
            self._connection.commit()
        cursor.close()

    def upgrade_database(self, version):
        pass

    def information(self) -> tuple:
        cursor = self._connection.cursor()
        cursor.execute('select * from session')
        result = cursor.fetchone()
        cursor.close()
        return result

    def insert(
        self        :   'SQLiteSession',
        phone_number:   str =   None,
        key         :   str =   None,
        guid        :   str =   None,
        url         :   str =   None
        ):
        cursor = self._connection.cursor()
        cursor.execute(
            'insert or replace into session (phone, auth, guid, agent)'
            ' values (?, ?, ?, ?)',
            (phone_number, key, guid, url)
        )
        self._connection.commit()
        cursor.close()

    @classmethod
    def from_string(cls, session: object,
                    file_name: str=None) -> (...):
        info = session.information()
        if file_name is None:
            if info is None:
                raise ValueError('file_name arg is not set')
            file_name = info[0]

        session = SQLiteSession(file_name)
        if info is not None:
            session.insert(*info)

        return session

class Urls(
    (str)
    ):
    
    def get_url() -> str:
        return choice(list(loads(__import__('urllib').request.urlopen('https://getdcmess.iranlms.ir/').read().decode('utf-8')).get('data').get('API').values()))
    
    giveUrl = lambda mode, key=None: SQLiteSession(key).information()[3] if key and 'https://' in SQLiteSession(key).information() else ('https://messengerg2c{}.iranlms.ir/'.format(str('56' if mode.lower() == 'mashhad' else '74' if mode.lower() == 'tehran' else str(randint(3, 74)))))

class clients(
    dict
    ):
    (
        web,
        android,
        rubx
        ) = (
            {
                'app_name'      :   'Main',
                'app_version'   :   '4.1.11',
                'platform'      :   'Web',
                'package'       :   'web.rubika.ir',
                'lang_code'     :   'fa'
                },
            {
                'app_name'      :   'Main',
                'app_version'   :   '2.8.1',
                'platform'      :   'Android',
                'package'       :   'ir.resaneh1.iptv',
                'lang_code'     :   'fa'
                },
            {
                'app_name'      :   'Main',
                'app_version'   :   '3.0.8',
                'platform'      :   'Android',
                'package'       :   'app.rbmain.a',
                'lang_code'     :   'en'
                }
        )

class Make(
    object,
    ):
    
    def evolution(message, key) -> (dict):
        
        res: dict = loads(Encryption(key).decrypt(message.get('data_enc')))
        
        if Errors.MadeError(res.get('status') or '', res.get('status_det') or ''):
            return res

class Connection(dict):

    timeout: int = 5

    @staticmethod
    def postion(
        url     :   (str),
        data    :   (dict),
        proxy   :   (dict),
        auth    :   (str),
        mode    :   (bool) = (False)
        ) -> (
            dict
            ):

            
            with session() as (
                sent
                ):

                for (item) in (range(3)):
                    
                    try:
                        return (Make.evolution((sent).post(url, json=(data) if not mode else dumps(data), timeout=Connection.timeout, proxies=proxy).json(), (auth)))
                    except Exception:
                        ...
                    #finally:
                    #raise ServerError('')

                else:
                    raise ServerError('`sorry`: device can\'t connect to the server and is not response, please checked your network.')

class GetData(
    (str)
    ):
    
    @staticmethod
    def api(
        **kwargs
        ) -> (
            Connection
            ):
        '''
        version =   '5' or '4',
        auth    =   'key',
        tmp     =   ...
        method  =   'methodName'
        data    =   input,
        mode     =  'mashhad',
        platform=   'rubx' or 'web',
        proxy   =   {'https':'127.0.0.1:9050'} # a dictionary type
        
        
        '''
        main: list = []
        
        if (kwargs.get('version') == '5'):
            main.extend(
                [
                    {
                        'api_version'   :   '5',
                        '{}'.format('auth' if kwargs.get('auth') else 'tmp_session') :   kwargs.get('auth') or kwargs.get('tmp'),
                        'data_enc'      :   Encryption(kwargs.get('auth')).encrypt(dumps({'input': kwargs.get('data'), 'client': clients.web if kwargs.get('platform') == 'web' else clients.rubx, 'method': kwargs.get('method')}))
                        }
                    ]
                )
        
        else:
            main.extend(
                [
                    {
                        'api_version'   :   '4',
                        'auth'          :   kwargs.get('auth'),
                        'client'        :   clients.android,
                        'method'        :   kwargs.get('method'),
                        'data_enc'      :   Encryption(kwargs.get('auth')).encrypt(dumps(kwargs.get('data')))
                }
                    ]
                )

        return (Connection.postion(Urls.giveUrl(kwargs.get('mode'), kwargs.get('auth')), main[0], kwargs.get('proxy'), kwargs.get('auth')))

class Version(str):
    __version__ =   '9.0.0'
    __author__  =   'saleh'
    __lisense__ =   'MIT'

class RubikaClient(
    object
    ):

    def __init__(
        self                :   ('Client'),
        session_key         :   (str),
        chat_id             :   (str)                   =   (None),
        username            :   (str)                   =   (None),
        app                 :   (str)                   =   ('rubx'),
        phone_number        :   (str)                   =   (None),
        device              :   (dict)                  =   (Device.defaultDevice),
        proxy               :   (dict)                  =   {'http': 'http://127.0.0.1:9050'},
        your_name           :   (str)                   =   (False),
        city                :   (str)                   =   ('mashhad'),
        banner              :   (bool)                  =   (False),
        creator_channel_open:   (bool)                  =   (False),
        platform            :   (str)                   =   (None),
        api_version         :   (str or int)            =   (None),
        headers             :   (dict or str or list)   =   (None),
        timeout             :   (int)                   =   (5),
        check_update        :   (bool)                  =   (False),
        lang_code           :   (str)                   =   ('fa'),
        base_logger         :   (typing.Union[str, logging.Logger])                   =   (None)
        ) -> (
            ...
            ):
        
        '''
        ### the main class
        ## inserts
        
        # USE:
        
            `client = Client('session-key')`
        
        # EXAMPLE:
            
            `with Client(...) as client:`
                `client.send_message(...)`
            
        
        # PARAMETERS:
        
            - 1- `self`: is a self obejct
            - 2- `session_key`: is account key [auth]
            - 3- `chat_id`: is your guid account
            - 4 - `username`: is your username account
            - 5 - `app`: is from app name
            - 6 - `phone_number`: is for using lib with phone_number and geting account key
            - 7 - `device`: is your account device for use token or thumbinline or ...
            - 8 - `your_name`: is for save info in a file.
            - 9 - `city`: is for your countery and city for using client server.
            - 10 - `banner`: is a boolean for print banner
            - 11 - `creator_channel_open`: is for joining your account in creator channel
            - 12 - `platform`: is for using user platform. examples: `rubx` or `web` or `android`
            - 13 - `api_version`: is for using api mode: `5` (for web and rubx) `4` (for rubika app [andorid]) `3` (for m.rubka.ir)
            - 14 - `headers`: is for set header to requests
            - 15 - `timeout`: is for requests timeout
            - 16 - `check_update`: is for checking lib new version
            - 17 - `lang_code`: to app lang code. `en`, `fa`, ...
            - 18 - `base_logger`: is for `__name__`
        '''
        
        (
            self.app,
            self.proxy,
            self.enc,
            self.city,
            self.platform,
            self.api_version,
            self.headers,
            self.username,
            self.chat_id,
            self.handling,
            self.phone,
            _log,
            self.timeout,
            self.lang_code,
            self.device
            ) = (
                app,
                proxy,
                Encryption(session_key),
                city,
                platform,
                api_version,
                headers,
                username,
                chat_id,
                {},
                phone_number,
                logging.getLogger(__name__),
                timeout,
                lang_code,
                device
                )
        
        Infos.citys.append(
            city
            )
        Infos.proxys.append(
            proxy
            )
        
        if banner:
            assert list(map(lambda character: (print(character, flush=True, end=''), sleep(0.01)), f'\n\033[0m< \033[31mrubx \033[0m> \033[36m | \033[31mstarted in \033[0m{str(datetime.datetime.now())}\033[31m| \033[0m{Version.__version__}\n'))
        
        if your_name:
            open('session_info.sty', 'w+').write('name fan: '+your_name+'\ntime started: '+str(datetime.datetime.now())+f'\key: {session_key}'+'\nyour ip: '+str(get('https://api.ipify.org').text))
        
        if session_key:
            self.auth: (str) = (session_key)
            Infos.auth_.append(session_key)
        
        elif phone_number:
            Login.SignIn(phone_number)
            
        else:
            warn('SessionWarning: please insert session key or phone_number in object')
            
        if creator_channel_open:
            
            self.set_channel_action('c0BGS8Y01535a4510be64fafc4610d43', 'Join')
            webbrowser.open('https://rubika.ir/theClient')

        if app == 'rubx':
            
            database = SQLiteSession(session_key)
            database.insert(self.phone, session_key, self.chat_id, Urls.get_url())

        if check_update:
            UpToDate(Version.__version__, 'https://raw.githubusercontent.com/Mester-Root/rubx/main/rubx/__version__').user()
        
        if isinstance(base_logger, str):
            base_logger: str = logging.getLogger(base_logger)
        
        elif not isinstance(base_logger, logging.Logger):
            base_logger: str = base

        class Loggers(dict):
            def __missing__(self, key) -> ...:
                if key.startswith('rub.'):
                    key = key.split('.', maxsplit=1)[1]

                return base_logger.getChild(key)

        self._log = Loggers()
        
        Connection.timeout: int = timeout
        
    def __call__(
        self
        ) -> ...:
        ...

    def __enter__(
        self    :   (
            'Client'
            )
        ):
        return (
            self
            )

    def __exit__(
        self    :   ('Client'),
        *args,
        **kwargs
        ) -> ...:
        ...

    def get_auth(self) -> (str or ...):
        return self.auth

Client = RubikaClient

class Method(
    Client
    ):

    def from_json(
        self       : Client,
        method_name: str,
        **kwargs
        ) -> (
            dict
            ):

            data: dict = {}
            
            assert map(lambda key: data.update({key: kwargs.get(key)}, list(kwargs.keys())))

            return (
                GetData.api(
                    version     =   self.api_version or '5',
                    method      =   method_name[0].lower() + method_name[1:],
                    auth        =   self.auth,
                    data        =   data,
                    proxy       =   self.proxy,
                    platform    =   self.plaform or 'rubx',
                    mode        =   self.city
                )
            )

class UserMethods:


    def __enter__(
        self    :   (
            'Client'
            )
        ):
        return (
            self
            )

    def __exit__(
        self    :   (
            'Client'
            ),
        *args,
        **kwargs
        ) -> (...):
        ...

    # lambda func methods.

    # this method for logout and delete sessions
    log_out                     =   lambda self='Client': GetData.api(version='5', auth=self.auth, method='logout', mode=self.city, proxy=self.proxy, data={}, platform='web')

    # this methpd for getting all chats
    get_chats                   =   lambda self='Client', start_id=None: GetData.api(version='5', method='getChats', data={'start_id': start_id}, mode=self.mode, platform='web', proxy=self.proxy)

    # this method for geting new chats
    get_chats_updates           =   lambda self='Client', state=None: GetData.api(version=self.api_version or '5', auth=self.auth, method='getChatsUpdates', data={'state'  :   state or str(round(datetime.today().timestamp()) - 250)}, mode=self.city, proxy=self.proxy, platform=self.platform or 'web')

    # it method is for get stickers 
    my_sticker_set              =   lambda self='Client': GetData.api(version=self.api_version or '5', method='getMyStickerSets', auth=self.auth, data={}, mode=self.city, proxy=self.proxy, platform=self.platform or 'web')

    # it method is for get account all folders
    get_folders                 =   lambda self='Client': GetData.api(version='5', auth=self.auth, method='getFolders', data={}, mode=self.city, platform='web', proxy=self.proxy)

    # setting methods

    get_privacy_setting         =   lambda self=Client: GetData.api(version=self.api_version or '5', method='getPrivacySetting', auth=self.auth, data={}, mode=self.city, platform=self.platform or 'web', proxy=self.proxy)
    get_my_sessions             =   lambda self=Client: GetData.api(version=self.api_version or '5', method='getMySessions', auth=self.auth, data={}, mode=self.city, platform=self.platform or 'web', proxy=self.proxy)
    get_two_passcode_status     =   lambda self=Client: GetData.api(version=self.api_version or '5', method='getTwoPasscodeStatus', auth=self.auth, data={}, mode=self.city, platform=self.platform or 'web', proxy=self.proxy)
    check_two_step_passcode     =   lambda self, password: GetData.api(version=self.api_version or '5', method='checkTwoStepPasscode', auth=self.auth, data={'password': password}, mode=self.city, platform=self.platform or 'web', proxy=self.proxy)
    change_password             =   lambda self, password, new_password, new_hint: GetData.api(version=self.api_version or '5', method='changePassword', auth=self.auth, data={'password': password, 'new_password': new_password, 'new_hint': new_hint}, mode=self.city, platform=self.platform or 'web', proxy=self.proxy)
    turn_off_two_step           =   lambda self, password: GetData.api(version=self.api_version or '5', method='turnOffTwoStep', auth=self.auth, data={'password': password}, mode=self.city, platform=self.platform or 'web', proxy=self.proxy)
    setup_two_step_verification =   lambda self, password, hint: GetData.api(version=self.api_version or '5', method='setupTwoStepVerification', auth=self.auth, data={'password': password, 'hint': hint}, mode=self.city, platform=self.platform or 'web', proxy=self.proxy)
    get_block_users             =   lambda self: GetData.api(version=self.api_version or '5', method='getBlockUsers', auth=self.auth, data={}, mode=self.city, platform=self.platform or 'web', proxy=self.proxy)
    request_recovery_email      =   lambda self, password, recovery_email: GetData.api(version=self.api_version or '5', method='requestRecoveryEmail', auth=self.auth, data={'password': password, 'recovery_email': recovery_email}, mode=self.city, platform=self.platform or 'web', proxy=self.proxy)
    verify_recovery_email       =   lambda self, password, code: GetData.api(version=self.api_version or '5', method='verifyRecoveryEmail', auth=self.auth, data={'password': password, 'code': code}, mode=self.city, platform=self.platform or 'web', proxy=self.proxy)
    get_contacts_updates        =   lambda self='Client', state=str(round(datetime.today().timestamp()) - 2000): GetData.api(version=self.api_version or '5', method='getContactsUpdates', auth=self.auth, data={'state': state}, mode=self.city, platform=self.platform or 'web', proxy=self.proxy)
    get_contacts                =   lambda self=Client : GetData.api(version=self.api_version or '5', method='getContacts', auth=self.auth, data={}, mode=self.city, platform=self.platform or 'web', proxy=self.proxy)

    @staticmethod
    def key_generation() -> (str):
        
        '''
        this method for create a fake auth key
        '''
        
        key: (str) = ''.join(__import__('random').sample(str('qweertyuiopasdfghjklzxcvbnm' * 2), 32))
        
        return ''.join(list(map(lambda a: chr((a - ord('a') + ord('\t')) % ord('\x1a') + ord('a')), (str(key[16:24] + key[:8] + key[24:32] + key[8:16]).encode('latin-1')))))
            

    @staticmethod
    def tmp_generation() -> (str):
        
        '''
        this method for creating a tmp session
        '''
        
        tmp_session, strings = {}, sample('abcdefghijklmnopqrstuvwxyz', 32)
        map(lambda i: tmp_session.update({choice(strings): ''}), range(32))
        
        return ''.join(list(tmp_session.keys()))

    @staticmethod
    def send_code(
        phone_number    :   (str),
        send_type       :   (str)   =   ('SMS'),
        password        :   (str)   =   None
        ) -> (
            dict
            ):

        '''
        send_type <- key/value -> SMS/Internal
        '''

        datas: dict = {'phone_number': f'98{phone_number[1:]}', 'send_type': send_type}
        if password:
            datas.update({'pass_key': password})
        return (GetData.api(version='5', tmp=UserMethods.tmp_generation(), method='sendCode', data=datas, mode=Infos.citys[0], platform='web'))

    @staticmethod
    def sign_in(
        phone_number    :   (str),
        phone_code_hash :   (str),
        phone_code      :   (str)
        ) -> (
            dict
            ):

        '''
        this method for login or signin with lib

        PARAMETERS:
            1- phone_number : phone number of target's account : 09XXXXXXXXX
            2- phone_code_hash : hash of code sent to phone
            3- phone_code : code sent to phone
        '''

        return GetData.api(
            version='5',
            method='signIn',
            mode=Infos.citys[0],
            platform='web',
            tmp=(UserMethods.tmp_generation()),
            proxy=Infos.proxys[0],
            data={
                'phone_number': f'98{phone_number[1:]}',
                'phone_code_hash': phone_code_hash,
                'phone_code': phone_code
                }
            )

    @staticmethod
    def register_device(auth: (str),
                        device: (dict) = Device.defaultDevice) -> (dict):
        
        '''
        this method for registering your acocunt
        '''
        
        return GetData.api(
            version='4',
            auth=auth,
            method='registerDevice',
            mode=Infos.citys[0],
            platform='android',
            proxy=Infos.proxys[0],
            data=(device)
            )

    @staticmethod
    def parsation (
        mode: (str),
        text: (str)
        ) -> (
            list[
                str
                ]
            ):

        results: list = []

        if (mode.upper().startswith('HTML')):

            realText: (str)  = Clean.html_cleaner(text)
            bolds   : (list) = findall(r'<b>(.*?)</b>', text)
            italics : (list) = findall(r'<i>(.*?)</i>', text)
            monos   : (list) = findall(r'<pre>(.*?)</pre>', text)
            bResult : (list) = [realText.index(i) for i in bolds]
            iResult : (list) = [realText.index(i) for i in italics]
            mResult : (list) = [realText.index(i) for i in monos]

            for bIndex, bWord in zip(bResult, bolds): 
                results.append(
                    {
                        'from_index'    :   bIndex,
                        'length'        :   len(bWord),
                        'type'          :   'Bold'
                        }
                    )

            for iIndex, iWord in zip(iResult, italics):
                results.append(
                    {
                        'from_index'    :   iIndex,
                        'length'        :   len(iWord),
                        'type'          :   'Italic'
                        }
                    )

            for mIndex, mWord in zip(mResult, monos):
                results.append(
                    {
                        'from_index'    :   mIndex,
                        'length'        :   len(mWord),
                        'type'          :   'Mono'
                        }
                    )

        elif (mode.lower().startswith('markdown')):
            return (Metas.checker(text))

    def checkAuth(self) -> (str or ...):

        '''
        this method for checking your auth ke
        '''

        if (not 'NOT_REGISTERED' in list(
            (
                GetData.api(
                    version='4',
                    auth=self.auth,
                    method='',
                    data={},
                    mode=self.city,
                    proxy=self.proxy,
                    platform='android'
                )
                ).keys()
            )):
            return {
                'status'    :   'ok'
                }
        else:
            return {
                'status'    :   'error'
                }

    def request_send_file(
        self,
        file: (str)
        ) -> (dict):
        
        return GetData.api(
            version='5',
            method='requestSendFile',
            auth=self.auth,
            mode=self.city,
            platform='web',
            data={
                'file_name': str(file.split('/')[-1]),
                'mime': file.split('.')[-1],
                'size': Path(file).stat().st_size
                }
            )

    def upload_file(self, file: (str)) -> (dict):
        
        if (not 'http' in (file)):
            frequest, bytef = RubikaClient.request_send_file(self, file), open(file, 'rb+').read()
            hash_send: str = frequest['access_hash_send']
            file_id: str = frequest['id']
            url: str = frequest['upload_url']
            
            header: dict = {
                'auth'              :   self.auth,
                'Host'              :   url.replace('https://', '').replace('/UploadFile.ashx', ''),
                'chunk-size'        :   str(Path(file).stat().st_size), 
                'file-id'           :   str(file_id),
                'access-hash-send'  :   hash_send,
                'content-type'      :   'application/octet-stream',
                'content-length'    :   str(Path(file).stat().st_size),
                'accept-encoding'   :   'gzip',
                'user-agent'        :   'okhttp/3.12.1'
            }
            
            if len(bytef) <= 131072:
                
                header['part-number'], header['total-part'] = '1', '1'
                
                while (1):
                    
                    try :
                        j = post(data=bytef, url=url, headers=header).text
                        j: (dict) = loads(j)['data']['access_hash_rec']
                        break
                    except Exception:
                        continue
        
                return [frequest, j]
            
            else:
                t: (int) = round(len(bytef) / 131072 + 1)
                
                for i in range(1,t+1) :
                    if i != t :
                        k = i - 1
                        k = k * 131072
                        while 1:
                            try:
                                header['chunk-size'], header['part-number'], header['total-part'] = '131072', str(i), str(t)
                                o = post(data=bytef[k:k + 131072], url=url, headers=header).text
                                o = loads(o)['data']
                                break
                            except Exception:
                                continue
                    else:
                        k = i - 1
                        k = k * 131072
                        while (1):
                            try:
                                header['chunk-size'], header['part-number'], header['total-part'] = str(len(bytef[k:])), str(i), str(t)
                                p = post(data=bytef[k:], url=url, headers=header).text
                                p = loads(p)['data']['access_hash_rec']
                                break
                            except Exception:
                                continue
                        return [frequest, p]

        else:
        
            frequest: (dict) = GetData.api(
                method='requestSendFile',
                auth=self.auth,
                mode=self.city,
                proxy=self.proxy,
                platform='web',
                data={
                    'file_name' :   file.split('/')[-1],
                    'mime'      :   file.split('.')[-1],
                    'size'      :   len(get(file).content)
                    }
                )
            
            hash_send: (str) = frequest['access_hash_send']
            file_id: (str) = frequest['id']
            url: (str) = frequest['upload_url']
            bytef: (str) = get(file).content
            
            header: (dict) = {
                'auth'              :   self.auth,
                'Host'              :   url.replace('https://', '').replace('/UploadFile.ashx', ''),
                'chunk-size'        :   str(len(get(file).content)),
                'file-id'           :   str(file_id),
                'access-hash-send'  :   hash_send,
                'content-type'      :   'application/octet-stream',
                'content-length'    :   str(len(get(file).content)),
                'accept-encoding'   :   'gzip',
                'user-agent'        :   'okhttp/3.12.1'
            }
            
            if len(bytef) <= 131072:
                header['part-number'], header['total-part'] = '1', '1'
                while (1):
                    try:
                        j = post(data=bytef, url=url, headers=header).text
                        j = loads(j)['data']['access_hash_rec']
                        break
                    except Exception:
                        continue
                return [frequest, j]
            
            else:
                t: (int) = round(len(bytef) / 131072 + 1)
                for i in range(1,t+1):
                    if (i != t):
                        k = i - 1
                        k = k * 131072
                        while 1:
                            try :
                                header['chunk-size'], header['part-number'], header['total-part'] = '131072', str(i), str(t)
                                o = post(data=bytef[k:k + 131072], url=url, headers=header).text
                                o = loads(o)['data']
                                break
                            except Exception:
                                continue
                    else:
                        k = i - 1
                        k = k * 131072
                        
                        while (1):
                            try:
                                header['chunk-size'], header['part-number'], header['total-part'] = str(len(bytef[k:])), str(i), str(t)
                                p = post(data=bytef[k:], url=url,headers=header).text
                                p = loads(p)['data']['access_hash_rec']
                                break
                            except Exception:
                                continue
                        return [frequest, p]

    @staticmethod
    def get_thumb_inline(
        image_bytes: (bytes)
        ) -> (bytes):
        
        from base64 import b64encode
        from io import BytesIO

        from PIL.Image import ANTIALIAS
        from PIL.Image import open as openF
        
        im: (bytes) = openF(BytesIO(image_bytes))
        (width, height) = (im.size)
        
        if (height > width):
            new_height: (int) = (40)
            new_width: (int)  = round(new_height * width / height)
        else:
            new_width: ((int))  = 40
            new_height: (int) = round(new_width * height / width)
        im = im.resize((new_width, new_height), ANTIALIAS)
        changed_image: (bytes) = BytesIO()
        im.save(changed_image, format='PNG')
        changed_image: (bytes) = changed_image.getvalue()

        return (b64encode(changed_image))
    
    @staticmethod
    def get_image_size(
        image_bytes: (
            bytes
            )
        ) -> (
            list[
                str,
                ]
            ):
        
        from io import BytesIO

        from PIL.Image import open as openF
        
        im = openF(BytesIO(image_bytes))
        (width, height) = (im.size)
        
        return [
            width,
            height
            ]

    def send_message(
        self                :   ('Client'),
        text                :   (str)   =   None,
        chat_id             :   (str)   =   None,
        username            :   (str)   =   None,
        link                :   (str)   =   None,
        metadata            :   (list)  =   [],
        parse_mode          :   (str)   =   None,
        button_id           :   (str)   =   None,
        sticker             :   (bool)  =   (False),
        emoji_character     :   (str)   =   ('😜'),
        sticker_id          :   (str)   =   ('5e07caefc34bb4876ca8a625'),
        sticker_set_id      :   (str)   =   ('5e07cac2c34bb4876ca8a624'),
        file_id             :   (str)   =   ('499582666'),
        w_h_ratio           :   (str)   =   ('1.0'),
        reply_to_message_id :   (str)   =   None,
        ) -> (
            dict or ...
            ):
            
            '''
            this method for sending a message
            
            '''
            
            if (username or link):
                chat_id: str = Maker.check_link(link=username or link, key=self.auth)
            
            data: (dict) = {
                    'object_guid'           :   (chat_id),
                    'rnd'                   :   str(randint(100000,999999999)),
                    'text'                  :   (text),
                    'reply_to_message_id'   :   (reply_to_message_id)
                }

            if sticker:
                data[
                    'sticker'
                    ]: (
                        dict
                        ) = {
                    'emoji_character'       :   emoji_character,
                    'w_h_ratio'             :   w_h_ratio,
                    'sticker_id'            :   sticker_id,
                    'file'                  :   {
                        'file_id'           :   file_id,
                        'mime'              :   'png',
                        'dc_id'             :   '32',
                        'access_hash_rec'   :   '911095004325419223254883204658',
                        'file_name'         :   'sticker.png'
                        },
                    'sticker_set_id'        :   sticker_set_id
                    }
            
            if button_id:
                data['aux_data']: (dict) = {
                    'button_id' :   button_id
                    }
            
            if metadata != [] :
                data['metadata']: (dict) = {'meta_data_parts' :   metadata}
            
            if parse_mode:
                data['metadata']: (dict) = {
                    'meta_data_parts'   :   RubikaClient.parsation(
                        str(
                            parse_mode
                            ),
                        text
                        )
                    }
                data['text']: (str) = Clean.html_cleaner(text) if parse_mode.upper() == 'HTML' else text.replace('**', '').replace('__', '').replace('`', '')

            return (
                GetData.api(
                    version     =   self.api_version or '5',
                    auth        =   self.auth,
                    method      =   'sendMessage',
                    mode        =   self.city,
                    platform    =   self.platform or 'web',
                    proxy       =   self.proxy,
                    data        =   data
                    )
                )

    def edit_message(
        self        :   ('Client'),
        message_id  :   (str),
        newText     :   (str),
        chat_id     :   (str)   =   (None),
        username    :   (str)   =   (None),
        link        :   (str)   =   (None),
        metadata    :   (list)  =   [],
        parse_mode  :   (str)   =   (None)
        ) -> (
            dict
            or
            ...
            ):

        if (username or link):
            chat_id: str = Maker.check_link(link=username or link, key=self.auth)

        data: (dict) = {
            'message_id'    :   message_id,
            'object_guid'   :   chat_id,
            'text'          :   newText
        }

        if metadata != []:
            data['metadata'] = {'meta_data_parts'    :   metadata}
        if parse_mode:
            data['metadata'] = {'meta_data_parts'    :   UserMethods.parsation(parse_mode, newText)}
            data['text'] = Clean.html_cleaner(newText) if parse_mode.upper() == 'HTML' else newText.replace('**', '').replace('__', '').replace('`', '')
        
        return (
            GetData.api(
                version     =   self.api_version or '5',
                auth        =   self.auth,
                method      =   'editMessage',
                data        =   data,
                platform    =   self.platform or 'web',
                proxy       =   self.proxy,
                mode        =   self.city
            )
        )

    def get_stickers_by_set_ids(
        self            :   ('Client'),
        sticker_set_ids : (
            list
            )
        ) -> (
            dict
            or
            ...
            ):

        '''
        sticker ids:  ['5e0c957a6282726921b7634n', '6e0c957a6282726921b7635l']
        '''
        
        return (
            GetData.api(
                version     =   self.api_version or '5',
                auth        =   self.auth,
                method      =   'getStickersBySetIDs',
                mode        =   self.city,
                proxy       =   self.proxy,
                platform    =   self.platform or 'web',
                data        =   {
                    'sticker_set_ids'   :   sticker_set_ids
                    },
            )
        )

    def delete_messages(
        self        :   ('Client'),
        message_ids :   (list),
        chat_id     :   (str)   =   (None),
        username    :   (str)   =   (None),
        link        :   (str)   =   (None),
        ) -> (
            dict
            ):
        
        '''
        self.deleteMessages(['1234566', ], 'TARGET-GUID')
        
        PARAMETRS:
            1- its a self object
            2- message_ids is for all message ids in list
            3- chat_id is chat or target guid
            4- username for dont using of chat_id parameter and to insert this parameter: '@username'
            5- link for dont using chat_id or username parameters and to insert: 'https://rubika.ir/username'
        '''
        
        if (username or link):
            chat_id: str = Maker.check_link(link=username or link, key=self.auth)
  
        return (GetData.api(
            version='5',
            method='deleteMessages',
            auth=self.auth,
            data={
                "object_guid":chat_id,
                "message_ids":message_ids,
                "type":"Global"
                    },
            platform='web',
            mode=self.city,
            proxy=self.proxy
        ))

    def get_user_info(
        self    : ('Client'),
        chat_id : (str) = (None),
        username: (str) = (None),
        link    : (str) = (None),
        ) -> (
            dict
            ):

        if (username or link):
            chat_id: str = Maker.check_link(link=username or link, key=self.auth)

        return (
            GetData.api(
                version='5',
                auth=self.auth,
                method='getUserInfo',
                data={
                    'user_guid' :   chat_id
                    },
                mode=self.mode,
                proxy=self.proxy,
                platform='web',
                )
            )

    def get_messages_interval(
        self    :   (Client),
        min_id  :   (str)   =   '0',
        sort    :   (str)   =   'FromMin',
        chat_id :   (str)   =   (None),
        username:   (str)   =   (None),
        link    :   (str)   =   (None),
        ) -> (
            dict
            ):

        '''
        self.get_messages_interval(min_id='last_message_id', sort='FromMax', chat_id='target-guid')
        
        PARAMETRS:
            1- min_id or middle message id is chat last message id
            2- sort is the time messages
            3- chat_id is target guid or uid chat
            4- username for do not using chat_id! to insert: '@username'
            5- link for dont using username or chat__id! to insert: 'https://rubika..ir/username'
        
        '''
        
        if (username or link):
            chat_id: str = Maker.check_link(link=username or link, key=self.auth)
        
        return (
            GetData.api(
                version='5',
                auth=self.auth,
                method='getMessagesInterval',
                data= {
                    'object_guid'       :   chat_id,
                    'sort'              :   sort,
                    'middle_message_id' :   min_id
                    },
                mode=self.city,
                platform='web',
                proxy=self.proxy,
                )
            )

    def get_object_by_username(
        self        :   (Client),
        username    :   (str)
        ) -> (
            dict
            ):

        '''
        username is @theUsername
        '''

        return (GetData.api(
            version='5',
            auth=self.auth,
            method='getObjectByUsername',
            data={
                'username'  :   username.replace(
                    '@',
                    ''
                    )
                },
            platform='web',
            mode=self.auth,
            proxy=self.proxy,
            
        ))

    def get_messages_by_id(
        self        :   ('Client'),
        chat_id     :   (str),
        message_ids :   (list)
        ) -> (
            dict
            ):
            
            '''
            self.get_messages_by_id('chat guid', ['12345...', ...])
            
            PARAMETERS:
                1- self is a self object
                2- chat_id is target guid
                3- message_ids is all message id in list class
            '''
            
            return (
                GetData.api(
                    version =   '5',
                    method  =   'getMessagesByID',
                    auth    =   self.auth,
                    data    =   {
                        'object_guid'   :   (
                            chat_id
                            ),
                        'message_ids'   :   (
                            message_ids
                            )
                        },
                    mode    =   self.city,
                    proxy   =   self.proxy,
                    platform=   'web'
                    )
                )

    def forward_messages(
        self        :   ('Client'),
        from_object_guid        :   (str),
        message_ids :   (list),
        to_object_guid          :   (str)
        ) -> (
            dict
            ):

            '''
            USE:
                self.forward_messages('from chat guid', ['1234...', ], 'to chat guid')
            
            PARAMETERS:
                1- self is a self object
                2- from_object_guid is for forwarded from a chat guid
                3- message_ids its a list for message ids
                4- to_object_guid is for forwarding to a chat_guid
            
            END
            '''

            return(
                GetData.api(
                    version='5',
                    method='forwardMessages',
                    auth=self.auth,
                    data={
                        'from_object_guid'  :   from_object_guid,
                        'message_ids'       :   message_ids,
                        'rnd'               :   str(randint(100000,999999999)),
                        'to_object_guid'    :   to_object_guid
                    },
                    mode=self.city,
                    proxy=self.proxy,
                    platform='web'
                )
            )

    def seen_chats(
        self        :   ('Client'),
        seen_list   :   (dict)
        ) -> (
            (
            dict
            ) or (
                ...
                )
            ):

        '''
        USE:
            self.seenChats({'guid':'message_id'})
        PARAMMETERS:
            1- self is a self object
            2- seen_list is a dictionary or list for seening all messages
        END.
        '''
        
        return(
            GetData.api(
                version='5',
                method='seenChats',
                auth=self.auth,
                data={
                    'seen_list'  :   seen_list
                    },
                mode=self.city,
                proxy=self.proxy,
                platform= self.platform if self.platform else 'web'
            )
        )

    def send_chat_activity(
        self        :   ('Client'),
        activity    :   (str),
        chat_id     :   (str)   =   (None),
        username    :   (str)   =   (None),
        link        :   (str)   =   (None),
        ) -> (
            dict
            ) or (
                ...
                ):
            
            
            '''
            this method for send typeing... in chat
            
            USE:
                self.send_chat_activity('typing...', 'user guid')
            PARAMETERS:
                1- self is a self object
                2- activity is for send a text in chat
                3- chat_id is chat guid
                4- username for dont using chat_id
                5- link for dont using chat_id or username.
            END
            
            '''

            if (username or link):
                chat_id: str = Maker.check_link(link=username or link, key=self.auth)            
            
            return(
                GetData.api(
                    version='5',
                    method='sendChatActivity',
                    auth=self.auth,
                    data={
                        'activity'      :   activity,
                        'object_guid'   :   chat_id
                    },
                    mode=self.city,
                    proxy=self.proxy,
                    platform='web'
                )
            )

    def set_pin_message(
        self        :   ('Client'),
        chat_id     :   (str),
        message_id  :   (str),
        action      :   (str)   =   ('Pin')
        ) -> (
            dict
            ) or (
                ...
                ):

            '''
            USE:
                self.set_pin_message('chat guid', 'message id')
            PARAMETERS:
                1- self is a self object
                2- chat_id is chat guid
                3- message_id is chat (others) message id
                4- action is actions type: 'Pin' and 'Unpin'
            END
            '''
            
            return (
                GetData.api(
                    version='4',
                    method='setPinMessage',
                    auth=self.auth,
                    data= {
                        'action'        :   action,
                        'message_id'    :   message_id,
                        'object_guid'   :   chat_id
                        },
                    mode=self.city,
                    proxy=self.proxy,
                    platform= self.platform or 'android'
                )
            )

    def set_block_user(
        self        :   ('Client'),
        chat_id     :   (str),
        action      :   (str)   =   ('Block')
        ) -> (
            dict
            or
            ...
            ):
            
            '''
            USE:
                self.set_block_user('user guid', action='Block')
            PARAMETERS:
                1- self is a self object
                2- chat_id is user guid
                3- action is actions type: 'Block' and 'Unblock'
            '''
            
            return (
                GetData.api(
                    version     =   self.api_version or '5',
                    method      =   'setBlockUser',
                    auth        =   self.auth,
                    data        ={
                        'action'    :   action,
                        'user_guid' :   chat_id
                        },
                    mode        =   self.city,
                    proxy       =   self.proxy,
                    platform    =   self.platform or 'web',
                    headers     =   self.headers
                )
            )

    def send_photo(
        self                :   ('Client'),
        chat_id             :   (str),
        file                :   (str),
        size                :   (list)  =   [],
        thumbnail           :   (str)   =   ('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'),
        caption             :   (str)   =   (None), 
        reply_to_message_id :   (str)   =   (None),
        ) -> (
            dict
            or
            ...
            ):
            
            
            '''
            this method for send photo image
            USE:
                self.send_photo('chat-guid', 'path/*.jpg')
            PARAMETERS:
                1- self is a self object
                2- chat_id is chat guid (other)
                3- file is file path
                4- size is file size = none
                5- thumbnail is file thumbnail
                6- caption is message file caption
                7- reply_to_message_id is for reply to message id in object
            '''
            
            uresponse: (dict) = UserMethods.upload_file(self, file)
            
            if ('.' in thumbnail):
                thumbnail: str = str(UserMethods.get_thumb_inline(open(file, 'rb').read() if not 'http' in file else get(file).content))
            if (size == []):
                size: list = UserMethods.get_image_size(open(file, 'rb').read() if not 'http' in file else get(file).content)
            
            file_inline: (dict) = {
                'dc_id'             :   uresponse[0]['dc_id'],
                'file_id'           :   uresponse[0]['id'],
                'type'              :   'Image',
                'file_name'         :   file.split('/')[-1],
                'size'              :   str(len(get(file).content if 'http' in file else open(file, 'rb').read())),
                'mime'              :   file.split('.')[-1],
                'access_hash_rec'   :   uresponse[1],
                'width'             :   size[0],
                'height'            :   size[1],
                'thumb_inline'      :   thumbnail
            }
            
            data: (dict) = {
                        'file_inline'           :   file_inline,
                        'object_guid'           :   chat_id,
                        'rnd'                   :   str(randint(100000,999999999)),
                        'reply_to_message_id'   :   reply_to_message_id
                    }
            
            if data:
                data['text']: (str) = caption
            
            return (
                GetData.api(
                    version     =   '5',
                    method      =   'sendMessage',
                    auth        =   self.auth,
                    data        =   data,
                    mode        =   self.city,
                    proxy       =   self.proxy,
                    platform    =   self.platform or 'web'
                )
            )

    def send_voice(
        self                :   ('Client'),
        file                :   (str),
        time                :   (str),
        chat_id             :   (str)   =   (None),
        caption             :   (str)   =   (None),
        reply_to_message_id :   (str)   =   (None),
        ) -> (dict or ...):
            
            '''
            this method for send voice
            
            USE:
            
                self.send_vvoice('path/file.mp3', '999')
            
            PARAMETERS:

                1- self is a self object
                
                2- file is file path (music)
                
                3- time is voice time
                
                4- chat_id is chat guid
                
                5- caption is message caption
                
                6- reply_to_message_id is for reply to message
            '''
    
            uresponse: (list) = UserMethods.upload_file(self, file)
            
            the_data: (dict) = {
                        'file_inline'           :   {
                            'dc_id'             :   uresponse[0]['dc_id'],
                            'file_id'           :   uresponse[0]['id'],
                            'type'              :   'Voice',
                            'file_name'         :   file.split('/')[-1],
                            'size'              :   str(len(get(file).content if 'http' in file else open(file, 'rb').read())),
                            'time'              :   time,
                            'mime'              :   file.split('.')[-1],
                            'access_hash_rec'   :   uresponse[1],
                        },
                        'object_guid'           :   chat_id,
                        'rnd'                   :   str(randint(100000,999999999)),
                        'reply_to_message_id'   :   reply_to_message_id
                        }
            
            if caption:
                the_data['text']: (str) = caption
            
            return (
                GetData.api(
                    version     =   self.api_version or '5',
                    method      =   'sendMessage',
                    auth        =   self.auth,
                    data        =   the_data,
                    mode        =   self.city,
                    proxy       =   self.proxy,
                    platform    =   self.platform or 'web'
                    )
            )

    def send_document(
        self                :   ('Client'),
        file                :   (str),
        chat_id             :   (str)   =   (None),
        caption             :   (str)   =   (None),
        reply_to_message_id :   (str)   =   (None),
        ) -> (
            dict
            or
            ...
              ):
            
            '''
            this method for send all files *
            
            
            USE:
            
                self.send_document('chat-guid', 'path/file.*')
            PARAMETERS:
            
                1- self is a self object
                
                2- chat_id is chat guid (other)
                
                3- file is file path
                
                4- caption is message file caption
                
                5- reply_to_message_id is for reply to message id in object
            '''
            
            uresponse: list[str, ] = UserMethods.upload_file(self, file)
            
            data: (dict) = {
                    'object_guid'           :  chat_id,
                    'reply_to_message_id'   :   reply_to_message_id,
                    'rnd'                   :   str(randint(100000,999999999)),
                    'file_inline'           :   {
                        'dc_id'             :   str(uresponse[0]['dc_id']),
                        'file_id'           :   (str(uresponse[0]['id'])),
                        'type'              :   'File',
                        'file_name'         :   file.split('/')[-1],
                        'size'              :   str(len(get(file).content if 'http' in file else open(file, 'rb').read())),
                        'mime'              :   file.split('.')[-1],
                        'access_hash_rec'   :   uresponse[1]
                    }
                }
            
            if caption:
                data['text']: (str) = caption
            
            return (
                GetData.api(
                    version     =   self.api_version or '5',
                    method      =   'sendMessage',
                    auth        =   self.auth,
                    data        =   data,
                    mode        =   self.city,
                    proxy       =   self.proxy,
                    platform    =   self.platform or 'web'
                )
            )

    def send_location(
        self                :   ('Client'),
        chat_id             :   (str),
        location            :   list[str, ],
        reply_to_message_id :   (str)   =   (None),
        ) -> (
            dict
            or
            ...
            ):
            
            '''
            this method for send your location
            
            USE:
                self.send_location('chat-guid', 'loc')
            
            PARAMETERS:
                1- self is a self object
                2- chat_id is chat guid (other)
                3- location is your loc
                4- reply_to_message is for reply message
            '''
            
            return (
                GetData.api(
                    version     =   self.api_version or '5',
                    methood     =   'sendMessage',
                    auth        =   self.auth,
                    data        =   {
                        'is_mute'               :   False,
                        'object_guid'           :   chat_id,
                        'rnd'                   :   str(randint(100000,999999999)),
                        'location'              :   {
                            'latitude'          :   location[0],
                            'longitude'         :   location[1]
                            },
                        'reply_to_message_id'   :   reply_to_message_id
                        },
                    mode        =   self.city,
                    platform    =   self.platform or 'web',
                    proxy       =   self.proxy
                )
            )

    def upload_avatar(
        self        :   ('Client'),
        file        :   (str),
        chat_id     :   (str)   =   (None),
        thumbnail   :   (str)   =   (None),
        ) -> (
            dict
            or
            ...
            ):
            
            '''
            this for upload avatar (profile image)
            
            USE:
                self.upload_avatar('file', 'your-guid')
            
            PARAMEETERS:
                1- self is a self object
                2- main is file
                3- chat_id is your chat id
                4- thumbnail is for thumbnail photo
            '''
            
            return (
                GetData.api(
                    version     =   self.api_version or '5',
                    method      =   'uploadAvatar',
                    auth        =   self.auth,
                    data        =   {
                        'object_guid'       :   self.chat_id or chat_id,
                        'thumbnail_file_id' :   str(UserMethods.upload_file(self, thumbnail or file)[0]['id']),
                        'main_file_id'      :   str(UserMethods.upload_file(self, file)[0]['id'])
                        },
                    modee       =   self.city,
                    proxy       =   self.proxy,
                    platform    =   self.platform or 'web',
                    headers     =   self.headers or {
                        'accept'        :   'application/json',
                        'user-agent'    :   __import__('pyuseragents').random()
                        }
                )
            )
            
    def get_chat_info(
        self    :   (Client),
        chat_id :   (str)
        ) -> (
            dict[str]
            or
            ...
            ):

            '''
            self.get_chat_info('chat-guid') # all object
            '''

            return (
                GetData.api(
                    version     =   self.api_version or '5',
                    method      =   f'get{str(Scanner.chat_type(chat_id)).title()}Info',
                    auth        =   self.auth,
                    data        =   {
                        f'get{__import__("tools").Scanner.chat_type(chat_id).title()}Info'
                    },
                    mode        =   self.city,
                    proxy       =   self.proxy,
                    platform    =   self.platform or 'web'
                )
            )

    def send_gif(
        self                :   Client,
        chat_id             :   str,
        file                :   str,
        width               :   str,
        height              :   str,
        thumbnail           :   str =   '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',
        caption             :   str =   (None),
        reply_to_message_id :   str =   (None)
        ) -> (
            dict or ...
            ):
            
            '''
            self.send_gif('chat-id', 'path/file', 100, 100)
            '''
            
            uresponse: list = UserMethods.upload_file(self, file)
            
            return (
                GetData.api(
                    version     =   self.api_version or '5',
                    method      =   'sendMessage',
                    auth        =   self.auth,
                    data        =   {
                        'object_guid'           :   chat_id,
                        'is_mute'               :   False,
                        'rnd'                   :   str(randint(100000,999999999)),
                        'file_inline'           :   {
                            'access_hash_rec'   :   uresponse[1],
                            'dc_id'             :   uresponse[0]['dc_id'],
                            'file_id'           :   str(uresponse[0]['id']),
                            'auto_play'         :   False,
                            'file_name'         :   file.split('/')[-1],
                            'width'             :   width,
                            'height'            :   height,
                            'mime'              :   file.split('.')[-1],
                            'size'              :   str(len(get(file).content if 'http' in file else open(file, 'rb').read())),
                            'thumb_inline'      :   thumbnail,
                            'type'              :   'Gif'
                        },
                        'text'                  :   caption,
                        'reply_to_message_id'   :   reply_to_message_id
                        },
                    mode        =   self.city,
                    proxy       =   self.proxy,
                    platform    =   self.platform or 'rubx'
                )
            )

    def update_profile(
        self        :   'Client',
        **kwargs    :   str
        ) -> (
            dict
            or
            ...
            ):

            '''
            self.update_profile(username='username')
            '''

            return (
                GetData.api(
                    version     =   self.api_version or '4',
                    method      =   'updateUsername' if 'username' in list(kwargs.keys()) else 'updateProfile',
                    auth        =   self.auth,
                    data        =   {
                        'username'   if 'username'   in list(kwargs.keys()) else None     :   kwargs.get('username')   or None,
                        'first_name' if 'first_name' in list(kwargs.keys()) else None     :   kwargs.get('first_name') or None,
                        'last_name'  if 'last_name'  in list(kwargs.keys()) else None     :   kwargs.get('last_name')  or None,
                        'bio'        if 'last_name'  in list(kwargs.keys()) else None     :   kwargs.get('bio')        or None,
                        'updated_parameters'                                              :   list(kwargs.keys())
                        },
                    mode        =   self.city,
                    proxy       =   self.proxy,
                    platform    =   self.platform or 'android'
                    
                )
            )

    def get_avatars(
        self    :   Client,
        chat_id :   str
        ) -> (
            dict
            or
            ...
            ):
            
            '''
            self.get_avatars('your-guid')
            '''
            
            return (
                GetData.api(
                    version     =   self.api_version or '5',
                    auth        =   self.auth,
                    method      =   'getAvatars',
                    data        =   {
                        'object_guid'   :   chat_id
                    },
                    mode        =   self.city,
                    proxy       =   self.proxy,
                    platform    =   self.platform or 'web'
                )
            )

    def delete_avatar(
        self        :   Client,
        chat_id     :   str,
        avatar_id   :   str
        ) -> (
            dict or ...
            ):
            
            '''
            self.delete_avatar('your-guid', 'id')
            '''
            
            return (
                GetData.api(
                    version     =   self.api_version or '5',
                    method      =   'deleteAvatar',
                    auth        =   self.auth,
                    data        =   {
                        'object_guid'   :   chat_id,
                        'avatar_id'     :   avatar_id
                    },
                    mode        =   self.city,
                    proxy       =   self.proxy,
                    platform    =   self.platform or 'web'
                )
            )

    def get_file(
        self            :   Client,
        download_type   :   str     =   'message' or 'my_inserts',
        save            :   bool    =   False,
        **kwargs        :   str or dict
        ) -> (
            dict or ...
            ):

            '''
            self.get_file('message', True, save_as='file.*', chat_id='chat-guid', message='msgid')
            '''

            result: bytes = b''

            if (download_type == 'message'):
                
                message: str or dict = kwargs.get('message')

                if type(message) != dict:
                    message: dict = UserMethods(auth=self.auth, banner=False, creator_channel_open=False).get_messages_by_id(kwargs.get('chat_id'), [str(message)])[0]

                file_id, size, dc_id, access_hash_rec, file_name = str(message['file_inline']['file_id']), message['file_inline']['size'], str(message['file_inline']['dc_id']), message['file_inline']['access_hash_rec'], message['file_inline']['file_name']

            else:
                file_id, size, dc_id, access_hash_rec, file_name = str(kwargs['file_id']), kwargs['size'], str(kwargs['dc_id']), kwargs['access_hash_rec']
            
            header: dict = {
                'auth'              :   self.auth,
                'file-id'           :   file_id,
                'access-hash-rec'   :   access_hash_rec
            }

            server: str = f'https://messenger{dc_id}.iranlms.ir/GetFile.ashx'

            if size <= 131072:

                header['start-index'], header['last-index'] = '0', str(size)
                
                while 1:

                    try:
                        result += get(url=server, headers=header).content
                        break
                    except Exception:
                        continue

            else:

                while 1:

                    try:
                        if 0 <= 131072:
                            header['start-index'], header['last-index'] = '0', str(size)
                            result += get(url=server, headers=header).content
                        
                        else:
                            for i in range(0, size, 131072):
                                header['start-index'], header['last-index'] = str(i), str(i+131072 if i+131072 <= size else size)
                                result += get(url=server, headers=header).content
                        break

                    except Exception:
                        continue
                    
            if save:

                open(kwargs.get('save_as') or f'{file_name}', 'wb+').write(result)

                return {
                    'status'    :   'saved',
                    'file_name' :   kwargs.get('save_as') or file_name
                    }

            else:
                return result

    def method(name: str, types: str, **data) -> dict or ...:
        
        import os
        methods: dict = __import__('json').load(open(os.path.join(os.path.dirname(os.getcwd()), 'methods.json')))
        
        def params(
            **kwargs
            ) -> dict:
            
            data: dict = methods.get(types).get(name).get('params')
            
            map(lambda key: data.update({key: kwargs.get(key)}, list(kwargs.keys())))
            
            return Method.from_json(name, data=data)

        return params(data)

    def set_setting(
        self    :   Client,
        **kwargs:   dict or str
        ) -> (
            dict or ...
            ):

        '''
        for type setSetting: Nobody, MyContacts, Everybody
        
        USE:
            self.set_setting(show_my_last_online='Nobody')
        
        PARAMS:
            show_my_last_online, show_my_phone_number, show_my_profile_photo, link_forward_message, can_join_chat_by
        '''

        return (
            GetData.api(
                version     =   self.api_version or '5',
                method      =   'setSetting',
                auth        =   self.auth,
                data        =   {
                    'settings'          :   kwargs,
                    'update_parameters' :   list(kwargs.keys())
                    },
                mode        =   self.city,
                proxy       =   self.proxy,
                platform    =   self.platform or 'web'
            )
        )

    def create_poll(
        self    :   Client,
        **kwargs:   str or dict
        ) -> (
            dict or ...
            ):

            '''
            self.send_poll(...)
            '''

            return (GetData.api(version=self.api_version or '4', method='createPoll', auth=self.auth, data=kwargs, mode=self.city, proxy=self.proxy, platform=self.platform or 'android'))

    def vote_poll(
        self            : Client,
        poll_id         : str,
        selection_index : int
        ) -> (
            dict or ...
            ):

            '''
            self.votte_poll('poll-id', '1')
            '''

            return (GetData.api(version=self.api_version or '4', auth=self.auth, method='votePoll', data={'poll_id': poll_id, 'selection_index': selection_index}, proxy=self.proxy, platform=self.platform or 'android', mode=self.city))

    def delete_chat_history(
        self            :   'Client',
        chat_id         :   str,
        last_message_id :   str
        ) -> (
            dict or ...
            ):
            
            '''
            self.deleteChatHistory('chat-guid', '0')
            '''
            
            return (
                GetData.api(
                    version     =   self.api_version or '5',
                    method      =   'deleteChatHistory',
                    auth        =   self.auth,
                    data        =   {
                        'object_guid'       :   chat_id,
                        'last_message_id'   :   last_message_id
                    },
                    mode        =   self.city,
                    proxy       =   self.proxy,
                    platform    =   self.platform or 'web'
                )
            )

    def search_global_objects(
        self        :   Client,
        search_text :  str
        )-> (
            dict or ...
            ):

            '''
            self.search_global_objects('Hey')
            '''

            return (
                GetData.api(
                    version     =   self.api_vesion or '5',
                    method      =   'searchGlobalObjects',
                    auth        =   self.auth,
                    data        =   {
                        'search_text'   :   search_text
                    },
                    mode        =   self.city,
                    proxy       =   self.proxy,
                    platform    =   self.platform or 'web'
                )
            )

    def get_poll_status(
        self    :   'Client',
        poll_id :   str
        ) -> (
            dict or ...
            ):
            
            '''
            self.get_poll_status('id')
            '''
            
            return (
                GetData.api(
                    version     =    self.api_version or '5',
                    auth        =    self.auth,
                    method      =   'getPollStatus',
                    data        =   {
                        'poll_id'   :   poll_id
                    },
                    mode        =   self.city,
                    proxy       =   self.proxy,
                    platform    =   self.platform or 'web'
                )
            )

    def get_poll_option_voters(
        self            :   Client,
        poll_id         :   str,
        selection_index :   str,
        start_id        :   str =   None
        ) -> (
            dict or ...
            ):
            
            '''
            self.get_poll_option_voters('id', 0)
            '''
            
            return (
                GetData.api(
                    version     =   self.api_version or '5',
                    method      =   'getPollOptinVoters',
                    auth        =   self.auth,
                    data        =   {
                        'poll_id'           :   poll_id,
                        'selection_index'   :   selection_index,
                        'start_id'          :   start_id
                    },
                    mode        =   self.city,
                    proxy       =   self.proxy,
                    platform    =   self.platform or 'web'
                )
            )

    def report_object(
        self                :   Client,
        chat_id             :   str,
        report_description  :   str =   None,
        report_type         :   str =   100,
        report_type_object  :   str =   None,
        message_id          :   str =   None,
        ) -> (
            dict or ...
            ):

            '''
            self.report_object('chat-guid', 'spam')
            '''

            return (
                GetData.api(
                    version     =   self.api_version or '4',
                    method      =   'reportObject',
                    auth        =   self.auth,
                    data        =   {
                        'object_guid'           :   chat_id,
                        'report_description'    :   report_description, 
                        'report_type_object'    :   Scanner.check_type(chat_id) if report_type_object else 'Object', 
                        'report_type'           :   report_type,
                        'meesage_id'            :   message_id
                        },
                    mode        =   self.city,
                    proxy       =   self.proxy,
                    platform    =   self.platform or 'android'
                    )
                )

    def get_link_from_app_url(
        self   : Client,
        app_url: str
        ) -> (
            dict or ...
            ):
            
            '''
            this method for open link on rubika and info link
            
            self.get_link_from_app_url('https://rubika.ir/channel/*')
            '''
            
            return (
                GetData.api(
                    version     =   self.api_version or '5',
                    auth        =   self.auth,
                    method      =   'getLinkFromAppUrl',
                    data        =   {
                        'app_url'   :   app_url
                        },
                    mode        =   self.city,
                    platform    =   self.platfrom or 'web',
                    proxy       =   self.proxy
                )
            )

    def send_chat_activity(
        self    :   Client,
        chat_id :   str,
        activity:   str =   'rubx-lib'
        ) -> (
            dict or ...
            ):
            
            '''
            self.send_chat_activity('chat-guid', is typing...')
            '''
            
            return (
                GetData.api(
                    version     =   self.api_version or '5',
                    auth        =   self.auth,
                    method      =   'sendChatActivity',
                    data        =   {
                        'object_guid'   :   chat_id,
                        'activity'      :   activity
                        },
                    mode        =   self.city,
                    platform    =   self.platfrom or 'web',
                    proxy       =   self.proxy
                )
            )

    def add_address_book(
        self        :   Client,
        phone       :   str,
        first_name  :   str =   None,
        last_name   :   str =   None
        ) -> (
            dict or ...
            ):
            
            '''
            self.add_address_book('09...', 'contact', 'my love')
            '''
            
            return (
                GetData.api(
                    version     =   self.api_version or '5',
                    auth        =   self.auth,
                    method      =   'addAddressBook',
                    data        =   {
                        'phone'     :   phone,
                        'first_name':   first_name,
                        'last_name' :   last_name
                        },
                    mode        =   self.city,
                    platform    =   self.platfrom or 'web',
                    proxy       =   self.proxy
                )
            )

    def delete_user_chat(
        self                    :   Client,
        chat_id                 :   str,
        last_deleted_message_id :   str
        ) -> (
            dict or ...
            ):
            
            '''
            self.delete_user_chat('chat-guid', '0')
            '''
            
            return (
                GetData.api(
                    version     =   self.api_version or '5',
                    auth        =   self.auth,
                    method      =   'deleteUserChat',
                    data        =   {
                        'user_guid'                 :   chat_id,
                        'last_deleted_message_id'   :   last_deleted_message_id
                        },
                    mode        =   self.city,
                    platform    =   self.platfrom or 'web',
                    proxy       =   self.proxy
                )
            )

    def search_globl_messages(
        self        :   Client,
        search_text :   str,
        types       :   str =   'Text',
        start_id    :   str =   '0'
        ) -> (
            dict or ...
            ):
            
            '''
            this method for search text in messages
            
            
            USE:
            
                self.search_global_messages('hi')
                
            PARAMS:
            
                1- self is a self object
                2- search_text is a text for searching
                3- type is a format action for types: Text, Photo, Gif, ...
                4- start_id is next chats
            '''
            
            return (
                GetData.api(
                    version     =   self.api_version or '5',
                    auth        =   self.auth,
                    method      =   'searchGlobalMessages',
                    data        =   {
                        'search_text'   :   search_text,
                        'type'          :   types,
                        'start_id'      :   start_id
                        },
                    mode        =   self.city,
                    platform    =   self.platfrom or 'web',
                    proxy       =   self.proxy
                )
            )

    def get_contacts_last_online(
        self        :   Client,
        chat_ids    :   list    =   None,
        usernames   :   list    =   None
        ) -> (
            dict
            ):
            
            '''
            self.get_contacts_last_online(['u0...', ])
            '''
            
            if usernames:
                with Client(self.auth, banner=False) as client:
                    chat_ids: list = [client.get_object_by_username(username)['chat']['object_guid'] for username in usernames]

            return (
                GetData.api(
                    version     =   self.api_version or '5',
                    auth        =   self.auth,
                    method      =   'getContactsLastOnline',
                    data        =   {
                        'user_guds' :   chat_ids
                        },
                    mode        =   self.city,
                    platform    =   self.platfrom or 'web',
                    proxy       =   self.proxy
                )
            )

    def get_abs_objects(
        self        :   Client,
        chat_ids    :   list    =   None
        ) -> (
            dict or ...
            ):
            
            '''
            self.get_abs_objects(['u0...', ])
            '''
            
            return (
                GetData.api(
                    version     =   self.api_version or '5',
                    auth        =   self.auth,
                    method      =   'getAbsObjects',
                    data        =   {
                        'objects' :   chat_ids
                        },
                    mode        =   self.city,
                    platform    =   self.platfrom or 'web',
                    proxy       =   self.proxy
                )
            )

    def get_messages_updates(
        self    :   Client,
        chat_id :   str,
        state   :   int =   None
        ) -> (
            dict or ...
            ):
            
            '''
            self.get_messages_updates('chat-guid')
            '''
            
            return (
                GetData.api(
                    version     =   self.api_version or '5',
                    auth        =   self.auth,
                    method      =   'getMessagesUpdates',
                    data        =   {
                        'object_guid'   :   chat_id,
                        'state'         :   state or str(round(datetime.datetime.today().timestamp()) - 250)
                      },
                    mode        =   self.city,
                    platform    =   self.platfrom or 'web',
                    proxy       =   self.proxy
                )
            )
    
    def send_mention(
        self                :   Client,
        chat_id             :   str,
        text                :   str,
        user_guid           :   str,
        mode                :   str =   'User',
        reply_to_message_id :   str =   None
        ) -> (dict or ...):
        
        '''
        self.send_mention('chat-guid', 'hi', 'u0...')
        '''
        
        return (
                GetData.api(
                    version     =   self.api_version or '5',
                    auth        =   self.auth,
                    method      =   'sendMessage',
                    data        =   {
                        'object_guid': chat_id,
                        'rnd': str(randint(100000,999999999)),
                        'text': text,
                        'reply_to_message_id': reply_to_message_id,
                        'metadata': {
                            'meta_data_parts':[
                                {
                                'type': 'MentionText',
                                'mention_text_object_guid': user_guid,
                                'from_index': 0,
                                'length': len(text),
                                'mention_text_object_type': mode
                                }
                                ]
                            }
                        },
                    mode        =   self.city,
                    platform    =   self.platfrom or 'web',
                    proxy       =   self.proxy
                )
            )

    def mention_text(
        self                :   'Client',
        chat_id             :   'str',
        user_guids          :   'list[str]',
        text                :   'str',
        reply_to_message_id :   'str'   =   None
        ) -> (dict or ...):

        '''
        self.mention_text('chat-guid', ['u0...'], '@hi@...')
        '''

        return (
                GetData.api(
                    version     =   self.api_version or '5',
                    auth        =   self.auth,
                    method      =   'sendMessage',
                    data        =   {'object_guid': chat_id, 'rnd': str(randint(100000,999999999)), 'reply_to_message_id': reply_to_message_id}.update({'text': Tags.checker(text, user_guids)[1], 'metadata': {'meta_data_parts': Tags.checker(text)[0]}}),
                    mode        =   self.city,
                    platform    =   self.platfrom or 'web',
                    proxy       =   self.proxy
                )
            )

    def add_folder(self: Client, name: str, **kwargs) -> (dict or ...):
        
        '''
        this method for adding folders in account
        
        USE:
            self.add_folder('name', include_chat_types = ['Contacts', ])
        
        PARAMS:
            1- self is a self object
            2- name is folder name
            3- kwags is: include_chat_types = ['Contacts', ...], ... include_chat_types: list, exclude_chat_types=None, include_object_guids=None, exclude_object_guids=None
        '''
        
        return (
                GetData.api(
                    version     =   self.api_version or '5',
                    auth        =   self.auth,
                    method      =   'addFolder',
                    data        =   {
                        'name'          :   name,
                        'is_add_to_top' :   'true'
                        }.update(kwargs),
                    mode        =   self.city,
                    platform    =   self.platfrom or 'web',
                    proxy       =   self.proxy
                )
            )

    def send_messag_api_call(
        self        :   Client,
        text        :   str,
        button_id   :   str,
        message_id  :   str,
        chat_id     :   str
        ) -> (
            dict or ...
            ):
            
            '''
            self.sendMessageAPICall(text='text', chat_id='b0Y0a2cafbaf668e282d2dc02a1fe2a7', button_id='newtextq_5f0069d7108cd24b2a958dad', message_id='7665754757')
            '''
            
            return (
                GetData.api(
                    version     =   self.api_version or '5',
                    auth        =   self.auth,
                    method      =   'sendMessageAPICall',
                    data        =   {
                        'text'          :   text,
                        'object_guid'   :   chat_id,
                        'message_id'    :   message_id,
                        'aux_data'      :   {
                            'button_id' :   button_id
                            }
                        },
                    mode        =   self.city,
                    platform    =   self.platfrom or 'web',
                    proxy       =   self.proxy
                )
            )

    def report_to_rubika_admin(
        self        :   Client,
        report_text :   str
        ) -> (dict):

        '''
        this method for send report to @supportbot
        '''

        client = Client(self.auth, banner=False)
        client.send_message(text='/start', chat_id='b0Y0a2cafbaf668e282d2dc02a1fe2a7'); sleep(0.5)
        client.send_message(text='سؤال دارم', chat_id='b0Y0a2cafbaf668e282d2dc02a1fe2a7', button_id='question')
        sleep(0.5)
        get: list = client.get_messages_interval('b0Y0a2cafbaf668e282d2dc02a1fe2a7', str(client.get_chat_info('b0Y0a2cafbaf668e282d2dc02a1fe2a7')['data']['chat']['last_message_id']))['data']['messages']
        client.send_messag_api_call(text='گزارش محتوای خلاف قوانین', object_guid='b0Y0a2cafbaf668e282d2dc02a1fe2a7', button_id='faq_5f0069d7108cd24b2a958dad', message_id=str(get[int(len(get)-1)]['message_id']))
        sleep(0.5)
        get: list = client.get_messages_interval('b0Y0a2cafbaf668e282d2dc02a1fe2a7', str(client.get_chat_info('b0Y0a2cafbaf668e282d2dc02a1fe2a7')['data']['chat']['last_message_id']))['data']['messages']
        client.send_messag_api_call(text=report_text, object_guid='b0Y0a2cafbaf668e282d2dc02a1fe2a7', button_id='newtextq_5f0069d7108cd24b2a958dad', message_id=str(get[int(len(get)-1)]['message_id']))

        return {'send_report_to':'supportbot', 'sended': True, 'report_text': report_text, 'sended_by':'rubx_lib'}

class GroupMethods:

    def __enter__(
        self    :   (
            'Client'
            )
        ):
        return (
            self
            )

    def __exit__(
        self    :   (
            'Client'
            ),
        *args,
        **kwargs
        ) -> (...):
        ...

    def ban_group_member(
        self            :   ('Client'),
        user_id         :   (str)   =   (None),
        member_username :   (str)   =   (None),
        chat_id         :   (str)   =   (None),
        link            :   (str)   =   (None),
        action          :   (str)   =   ('Set'),
        ) -> (
            dict
            ):

        '''
        self.ban_group_member(user_id='chat id or guid', chat_id='chat guid')
        
        PARAMETRS:
            1- self - self object
            2- user_id - target guid or chat id
            3- member_username - to do nt using user_id and to insert: '@username'
            4- link - to dont using chat_id and to insert: 'https://rubika.ir/+'
            5- action is actions type: 'Set', 'Unset'
        '''

        if (link):
                chat_id: str = Maker.check_link(link=link, key=self.auth)
        if (member_username):
            user_id: str = Maker.check_link(link=member_username, key=self.auth)
        
        return (
            GetData.api(
                version     =   self.api_version or '4',
                method      =   'banGroupMember',
                auth        =   self.auth,
                data        =   {
                        'group_guid'    :   chat_id,
                        'member_guid'   :   user_id,
                        'action'        :   action
                        },
                proxy       =   self.proxy,
                mode        =   self.city,
                platform    =   self.platfrom or 'android',
                )
            )

    def add_group_members(
        self        :   'Client',
        user_ids    :   (list)  =  (None),
        usernames   :   (list)  =   (None),
        chat_id     :   (str)   =   (None)
        ) -> (
            dict
            ):
            
            '''
            self.add_group_members(['user-guid', ], chat_id='group-guid')
            
            PARAMETERS:
                1- self object
                2- user_ids is targets guid
                3- usernames for dont using user_ids to inserts: ['@username', '@...']
                4- chat_id is group guid
               
            '''

            if (usernames):
                user_ids    :   (
                    (
                        list
                        )
                    )    =       []
                with Client(self.auth, banner=False) as app:
                    assert list(map(lambda user: user_ids.append(str(app.getObjectByUsername(user.replace('@', ''))['chat']['object_guid'])), (usernames)))

            return (
                GetData.api(
                    version='5',
                    method='addGroupMembers',
                    auth=self.auth,
                    data={
                        'group_guid'    :   chat_id,
                        'member_guids'  :   user_ids
                        },
                    mode=self.city,
                    proxy=self.proxy,
                    paltform='web',
                    )
                )

    def get_group_admin_members(
        self        :   ('Client'),
        chat_id     :   (str)   =   (None),
        username    :   (str)   =   (None),
        link        :   (str)   =   (None)
        ) -> (
            dict
            ):
            
            '''
            self.get_group_admin_members('chat guid')
            
            PARAMETERS:
                -1 self is a self object
                -2 chat_id is chat guid
                -3 username is for dont using chat_id and to insert: '@username'
                -4 link is for dont using chat_id or username and to insert: 'https://rubika.ir/'
                - END :)
            '''
            
            if (username or link):
                chat_id: str = Maker.check_link(link=username or link, key=self.auth)

            return (
                GetData.api(
                    version='5',
                    method='getGroupAdminMembers',
                    auth=self.auth,
                    data={
                        'group_guid'  :   (
                            chat_id
                            )
                        },
                    mode=self.city,
                    platform='web',
                    proxy=self.proxy
                    )
                )

    def set_group_default_access(
        self        :   ('Client'),
        access_list :   (list),
        chat_id     :   (str)   =   (None),
        username    :   (str)   =   (None),
        link        :   (str)   =   (None)
        ) -> (
            dict
            or
            ...
            ):
            
            
            '''
            from rubx import accesses
            self.set_group_default_access([accesses.SendMessages, ...], 'chat guid')
            
            PARAMETERS:
                1- self is a self object
                2- access_list is a list for users access
                3- chat_id is chat guid
                4- username is for dont using chat_id and to insert: '@username'
                5- link is for dont using chat_id or username and to insert: 'https://rubika.ir/username'
                - END :)
            '''

            if (username or link):
                chat_id: str = Maker.check_link(link=username or link, key=self.auth)
            
            return (
                GetData.api(
                    version     =   self.api_version or '4',
                    method      =   'setGroupDefaultAccess',
                    auth        =   self.auth,
                    data        =   {
                        'access_list'   :   (access_list),
                        'group_guid'    :   (chat_id)
                        },
                    mode        =   self.city,
                    proxy       =   self.proxy,
                    platform    =   self.platform or 'android'
                    )
                )

    def get_group_all_members(
        self        :   ('Client'),
        chat_id     :   (str)   =   (None),
        start_id    :   (str)   =   (None)
        ) -> (
            dict
            or
            ...
            ):
            
            '''
            self.get_group_all_members('chat guid')
            
            PARAMETERS:
                1- chat_id is chat guid (group type)
                2- start_id is for geting next member. and to get start_id: get key 'next_start_id'
                - END
            '''

            return (
                GetData.api(
                    version     =   self.api_version or '5',
                    method      =   'getGroupAllMembers',
                    auth        =   self.auth,
                    data        =   {
                        'group_guid'    :   (chat_id),
                        'start_id'      :   (start_id)
                        },
                    proxy       =   self.proxy,
                    mode        =   self.city,
                    playform    =   self.platform or 'web'
                    )
                )

    def get_group_info(
        self    :   ('Client'),
        chat_id :   (str)   =   (None)
        ) -> (
            dict
            or
            ...
            ):

            '''
            self.get_group_info('chat guid')
            
            PARAMETERS:
                1- self is a self object
                2- chat_id is group guid
                - END
            '''

            return (
                GetData.api(
                    version     =   self.api_version or '5',
                    method      =   'getGroupInfo',
                    auth        =   self.auth,
                    data        =   {
                        'group_guid'    :   (chat_id)
                    },
                    mode        =   self.city,
                    proxy       =   self.proxy,
                    platform    =   self.platform or 'web'
                )
            )

    def get_group_link(
        self    :   ('Client'),
        chat_id :   (str)
        ) -> (
            str
            or
            ...
            ):
            
            '''
            self.get_group_link('group-guid')
            note: this method for admin group
            
            PARAMETERS:
                1- self is a self object
                2- chat_id is group guid
                - END
            '''
            
            return(
                GetData.api(
                    version     =   self.api_version or '5',
                    auth        =   self.auth,
                    method      =   'getGroupLink',
                    data        =   {
                        'group_guid'    :   (chat_id)
                    },
                    mode        =   self.city,
                    platform    =   self.platform or 'web',
                    proxy       =   self.proxy
                )
            )

    def set_group_link(
        self    :   ('Client'),
        chat_id :   (str)   =   (None)
        ) -> (
            dict
            or
            ...
            ):
            
            '''
            self.get_group_link('group-guid')
            note: this method for admin group
            
            PARAMETERS:
                1- self is a self object
                2- chat_id is group guid
                - END
            '''
            
            return(
                GetData.api(
                    version     =   '5',
                    auth        =   self.auth,
                    method      =   'setGroupLink',
                    data        =   {
                        'group_guid'    :   (chat_id)
                    },
                    mode        =   self.city,
                    platform    =   'web',
                    proxy       =   self.proxy
                )
            )

    def set_group_timer(
        self    :   ('Client'),
        chat_id :   (str),
        time    :   (str),
        ) -> (
            dict
            or
            ...
            ):
            
            '''
            self.get_group_link('group-guid')
            note: this method for admin group
            
            PARAMETERS:
                1- self is a self object
                2- chat_id is group guid
                3- time is a time for group timer
                - END
            '''
            
            return (
                GetData.api(
                    version     =   self.api_version or '4',
                    method      =   'editGroupInfo',
                    auth        =   self.auth,
                    data        =   {
                        'group_guid'            :   chat_id,
                        'slow_mode'             :   time,
                        'updated_parameters'    :   ['slow_mode']
                        },
                    mode        =   self.city,
                    proxy       =   self.proxy,
                    platform    =   self.platform or 'android'
                )
            )

    def set_group_admin(
        self            :   ('Client'),
        access_list     :   (list)  =   (None),
        chat_id         :   (str)   =   (None),
        user_id         :   (str)   =   (None),
        member_username :   (str)   =   (None),
        action          :   (str)   =   ('SetAdmin')
        ) -> (
            dict or ...
            ):

            '''
            USE:
                from rubx.accesses import admin
                self.set_group_admin([admin.SendMessages, ...], 'group guid', 'user guid')
            PARAMETERS:
                1- self is a self object
                2- access_list is a list for member access
                3- chat_id is group guid
                4- user_id is member guid
                5- member_username is member username (for dont using chat_id) and to insert: '@username'
                6- action is a action type. actions: 'SetAdmin', UnsetAdmin''
            '''
            
            if (member_username):
                chat_id: (str) = Client(self.auth, banner=False).get_object_by_username(member_username)['chat']['object_guid']

            return (
                GetData.api(
                    version     =   '5',
                    method      =   'setGroupAdmin',
                    auth        =   self.auth,
                    data        =   {
                        'group_guid'    :   chat_id,
                        'access_list'   :   access_list,
                        'action'        :   action,
                        'member_guid'   :   user_id
                        },
                    mode        =   self.city,
                    proxy       =   self.proxy,
                    platform    =   'web'
                    )
                )

    def join_group(
        self    :   ('Client'),
        link    :   (str) or ...
        ) -> (
            dict or ... or GetData.api
            ):
            
            '''
            (this method for join to groups.)
            
            USE:
                self.join_group('https://rubika.ir/joing/...')
            PARAMETERS:
                1- self is a self object.
                2- link is a link rubika group.
            '''
            
            return (
                GetData.api(
                    version     =   self.api_version or '5',
                    method      =   'joinGroup',
                    auth        =   self.auth,
                    data        =   {
                        'hash_link'   :   link.split('/')[-1]
                        },
                    mode        =   self.city,
                    proxy       =   self.proxy,
                    platform    =   self.platform or 'web'
                )
            )

    def group_preview_by_join_link(
        self    :   ('Client'),
        link    :   (str)
        ) -> (
            dict
            ) or (
                ...
                ):
                '''
                (this method for get group link info by join link)
                
                USE:
                    self.group_preview_by_join_link('https://rubika.ir/joing/...')
                PARAMETERS:
                    1- self is a self object.
                    2- link is a link rubika group.
                '''
                
                return (
                    GetData.api(
                        version     =   self.api_version or '5',
                        method      =   'groupPreviewByJoinLink',
                        auth        =   self.auth,
                        data        =   {
                            'hash_link'   :   link.split('/')[-1]
                            },
                        mode        =   self.city,
                        proxy       =   self.proxy,
                        platform    =   self.platform or 'web'
                    )
                )

    def leave_group(
        self    :   ('Client'),
        chat_id :   (str)
        ) -> (
            dict
            or
            ...):
            
            '''
            this method for leave the group
            
            USE:
                self.leave_group('group guid') # g0...
            PARAMETERS:
                1- self is a self oobject
                2- chat_id is group guid
            '''
            
            return (
                GetData.api(
                    version     =   self.api_version or ('5'),
                    method      =   'leaveGroup',
                    auth        =   self.auth,
                    data        =   {
                        'group_guid'    :   (chat_id)
                        },
                    mode        =   self.city,
                    proxy       =   self.proxy,
                    platform    =   self.platform or ('web')
                )
            )

    def create_objcet_voice_chat(
        self    :   ('Client'),
        chat_id :   (str)
        ) -> (
            dict or ...
            ):

            '''
            self.start_voice_chat('chat-guid')
            '''
            
            return (
                GetData.api(
                    version     =   self.api_version or '5',
                    method      =   f'create{Scanner.check_type(chat_id)}VoiceChat',
                    data        =   {
                        f'{Scanner.check_type(chat_id).lower()}_guid'   :   chat_id,
                        },
                    auth        =   self.auth,
                    proxy       =   self.proxy,
                    platform    =   self.platform or 'web',
                    mode        =   self.city
                )
            )

    def set_object_voice_chat_setting(
        self            :   'Client',
        chat_id         :   (str),
        voice_chat_id   :   (str),
        title           :   (str)
        ) -> (
            dict or ...
            ):
            
            '''
            self.set_object_voice_chat_settin('chat-guid', 'id', 'the title')
            '''
            
            return (
                GetData.api(
                    version     =   self.api_version or '5',
                    auth        =   self.auth,
                    method      =   f'set{Scanner.check_type(chat_id)}VoiceChatSetting',
                    data        =   {
                        f'{Scanner.check_type(chat_id).lower()}_guid'   :   chat_id,
                        'voice_chat_id'                                 :   voice_chat_id,
                        'title'                                         :   title ,
                        'updated_parameters'                            :   ['title']
                    },
                    mode        =   self.city,
                    proxy       =   self.proxy,
                    platform    =   self.platform or 'web'
                )
            )

    def discard_object_voice_chat(
        self            :   'Client',
        chat_id         :   (str),
        voice_chat_id   :   (str),
        ) -> (
            dict
            or
            ...
            ):
            
            '''
            self.discard_object_voice_chat('chat-guid', 'id')
            '''
            
            return (
                GetData.api(
                    version     =   self.api_version or '5',
                    auth        =   self.auth,
                    method      =   f'discard{Scanner.check_type(chat_id)}VoiceChat',
                    data        =   {
                        f'{Scanner.check_type(chat_id).lower()}_guid'   :   chat_id,
                        'voice_chat_id'                                 :   voice_chat_id
                        },
                    mode        =   self.city,
                    platform    =   self.platfrom or 'web',
                    proxy       =   self.proxy
                )
            )

    def set_action_chat(
        self    :   Client,
        chat_id :   str,
        action  :   str
        ) -> (
            dict or ...
            ):

            '''
            USE:
                self.set_action_chat('chat-guid', 'Pin')
            PARAMS:
                1- self is a self object
                2- chat_id is chat guid
                3- action is a action type. actions: 'Mute', 'Unmute' | 'Pin', 'Unpin'
            '''

            return (
                GetData.api(
                    version     =   self.api_version or '5',
                    auth        =   self.auth,
                    method      =   'setActionChat',
                    data        =   {
                        'object_guid'   :   chat_id,
                        'action'        :   action
                        },
                    mode        =   self.city,
                    platform    =   self.platfrom or 'web',
                    proxy       =   self.proxy
                )
            )

    def join_group_voice_chat(
        self            :   Client,
        chat_id         :   str,
        voice_chat_id   :   str,
        self_object_guid:   str,
        sdp_offer_data  :   str =   '''v=0\r\no=- 7025254686977085379 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE 0\r\na=extmap-allow-mixed\r\na=msid-semantic: WMS LjIerKYwibTOvR0Ewwk1PBsYYxTInaoXObBE\r\nm=audio 9 UDP/TLS/RTP/SAVPF 111 63 103 104 9 0 8 106 105 13 110 112 113 126\r\nc=IN IP4 0.0.0.0\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:6Hy7\r\na=ice-pwd:pyrxfUF+roBFRHDy6qgiKSAp\r\na=ice-options:trickle\r\na=fingerprint:sha-256 8C:90:E9:0C:E7:A4:79:7E:BF:78:81:ED:A7:19:82:64:71:F7:21:AB:43:4F:4B:3A:4C:EB:B5:3C:6A:01:CB:13\r\na=setup:actpass\r\na=mid:0\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid\r\na=sendrecv\r\na=msid:LjIerKYwibTOvR0Ewwk1PBsYYxTInaoXObBE 00f6113c-f01a-447a-a72e-c989684b627a\r\na=rtcp-mux\r\na=rtpmap:111 opus/48000/2\r\na=rtcp-fb:111 
transport-cc\r\na=fmtp:111 minptime=10;useinbandfec=1\r\na=rtpmap:63 red/48000/2\r\na=fmtp:63 111/111\r\na=rtpmap:103 ISAC/16000\r\na=rtpmap:104 ISAC/32000\r\na=rtpmap:9 G722/8000\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:106 CN/32000\r\na=rtpmap:105 CN/16000\r\na=rtpmap:13 CN/8000\r\na=rtpmap:110 telephone-event/48000\r\na=rtpmap:112 telephone-event/32000\r\na=rtpmap:113 telephone-event/16000\r\na=rtpmap:126 telephone-event/8000\r\na=ssrc:1614457217 cname:lYBnCNdQcW/DEUj9\r\na=ssrc:1614457217 msid:LjIerKYwibTOvR0Ewwk1PBsYYxTInaoXObBE 00f6113c-f01a-447a-a72e-c989684b627a\r\n'''
        ) -> (
            dict or ...
            ):

            '''
            self.join_group_voice_chat('chat-guid', 'id', 'your-guid', ...)
            '''

            return (
                GetData.api(
                    version     =   self.api_version or '5',
                    auth        =   self.auth,
                    method      =   'joinGroupVoiceChat',
                    data        =   {
                        'chat_guid'         :   chat_id,
                        'voice_chat_id'     :   voice_chat_id,
                        'sdp_offer_data'    :   sdp_offer_data,
                        'self_object_guid'  :   self_object_guid
                    },
                    mode        =   self.city,
                    platform    =   self.platfrom or 'web',
                    proxy       =   self.proxy
                )
            )

    get_display_as_in_group_voice_chat = lambda self, chat_id: GetData.api(version=self.api_version or '5', method='getDisplayAsInGroupVoiceChat', auth=self.auth, data={'chat_guid': chat_id}, mode=self.city, platform=self.platform or 'web', proxy=self.proxy)

    def leave_group_voice_chat(
        self            :   Client,
        chat_id         :   str,
        voice_chat_id   :   str
        ) -> (
            dict or ...
            ):
            
            '''
            self.leave_group_voice_chat('chat-guid', 'id')
            '''
            
            return (
                GetData.api(
                    version     =   self.api_version or '5',
                    auth        =   self.auth,
                    method      =   'leaveGroupVoiceChat',
                    data        =   {
                        'chat_guid'     :   chat_id,
                        'voice_chat_id' :   voice_chat_id
                        },
                    mode        =   self.city,
                    platform    =   self.platfrom or 'web',
                    proxy       =   self.proxy
                )
            )

    def set_group_voice_chat_setting(
        self            :   Client,
        chat_id         :   str,
        voice_chat_id   :   str,
        **kwargs        :   (dict or str)
        ) -> (
            dict or ...
            ):
            
            '''
            self.set_group_voice_chat_setting('chat-guid', 'id', title='Hey')
            '''
            
            return (
                GetData.api(
                    version     =   self.api_version or '5',
                    auth        =   self.auth,
                    method      =   'setGroupVoiceChatSetting',
                    data        =   {
                        'chat_guid'     :   chat_id,
                        'voice_chat_id' :   voice_chat_id,
                        'updated_parameters'    :   list(kwargs.keys())
                        }.update(kwargs),
                    mode        =   self.city,
                    platform    =   self.platfrom or 'web',
                    proxy       =   self.proxy
                )
            )

    def edit_group_info(
        self                        :   Client,
        chat_id                     :   str,
        title                       :   str =   None,
        description                 :   str =   None,
        chat_history_for_new_members:   str =   None
        ) -> (
            dict or ...
            ):
            
            '''
            self.edit_group_info('chat-guid', 'name', 'bio')
            
            actions: Hidden, Visible
            '''
            
            return (
                GetData.api(
                    version     =   self.api_version or '5',
                    auth        =   self.auth,
                    method      =   'editGroupInfo',
                    data        =   {
                        'group_guid'        :   chat_id,
                        'title'             :   title,
                        'description'       :   description,
                        'updated_parameters':   ['title', 'description', 'chat_history_for_new_members' if chat_history_for_new_members else None]
                        }.update({'chat_history_for_new_members': chat_history_for_new_members} if chat_history_for_new_members else {}),
                    mode        =   self.city,
                    platform    =   self.platfrom or 'web',
                    proxy       =   self.proxy
                )
            )

    def get_banned_chat_members(
        self    :   Client,
        chat_id :   str,
        start_id:   str =   None
        ) -> (
            dict or ...
            ):
            
            '''
            self.get_banned_group_members('chat-guid') # get 'next_start_id' from respone to star_id param
            '''
            
            return (
                GetData.api(
                    version     =   self.api_version or '4',
                    auth        =   self.auth,
                    method      =   f'getBanned{Scanner.check_type(chat_id)}Members',
                    data        =   {
                        f'{Scanner.check_type(chat_id).lower()}_guid'        :   chat_id,
                        }.update({'start_id' : start_id} if start_id else {}),
                    mode        =   self.city,
                    platform    =   self.platfrom or 'android',
                    proxy       =   self.proxy
                )
            )

    def get_group_mention_list(
        self            :   Client,
        chat_id         :   str =   None,
        search_mention  :   str =   None
        ) -> (
            dict or ...
            ):
            
            '''
            self.get_group_mention_list('chat-guid')
            '''
            
            return (
                GetData.api(
                    version     =   self.api_version or '5',
                    auth        =   self.auth,
                    method      =   'getGroupMentionList',
                    data        =   {
                        'group_guid'    :   chat_id,
                        'search_mention':   search_mention
                        },
                    mode        =   self.city,
                    platform    =   self.platfrom or 'web',
                    proxy       =   self.proxy
                )
            )

    def delete_no_access_group_chat(self: Clean,
                                    chat_id: str) -> (dict or ...):
        
        '''
        self.delete_no_access_group_chat('group-guid')
        '''
        
        return (
                GetData.api(
                    version     =   self.api_version or '5',
                    auth        =   self.auth,
                    method      =   'deleteNoAccessGroupChat',
                    data        =   {
                        'group_guid'    :   chat_id
                        },
                    mode        =   self.city,
                    platform    =   self.platfrom or 'web',
                    proxy       =   self.proxy
                )
            )

class ChannelMethods:
    
    def __enter__(
        self    :   (
            'Client'
            )
        ):
        return (
            self
            )

    def __exit__(
        self    :   (
            'Client'
            ),
        *args,
        **kwargs
        ) -> (...):
        ...
    
    set_channel_link        =   lambda self, chat_id: GetData.api(version=self.api_version or '5', method='setChannelLink', auth=self.auth, data={'channel_guid': chat_id}, mode=self.city, platform=self.platform or 'web', proxy=self.proxy)
    check_channel_username  =   lambda self, username: GetData.api(version=self.api_version or '5', method='checkChannelUsername', auth=self.auth, data={'username': username}, mode=self.city, platform=self.platform or 'web', proxy=self.proxy)
    delete_channel          =   lambda self, chat_id: GetData.api(version=self.api_version or '5', method='removeChannel', auth=self.auth, data={'channel_guid': chat_id}, mode=self.city, platform=self.platform or 'web', proxy=self.proxy)

    def add_channel_members(
    
        self        :   'Client',
        user_ids    :   (list),
        chat_id     :   (str)
        ) -> (
            dict
            ):

            '''

            self.add_channel_members(['user guid', ]. chat_id='channel guid')
            
            PARAMETERS:
                1- user_ids a list user guids
                3- chat_id is channel guid
            '''

            return (GetData.api(
                version     =   self.api_version or '5',
                method      =   'addChannelMembers',
                auth        =   self.auth,
                data        =   {
                    'channel_guid'  :   chat_id,
                    'member_guids'  :   user_ids
                    },
                mode        =   self.city,
                platform    =   self.platform or 'web',
                proxy       =   self.proxy
                )
                    )
    
    def get_channel_all_members(
        self            :   ('Client'),
        chat_id         :   (str)   =   (None),
        search_text     :   (str)   =   (None),
        start_id        :   (str)   =   (None)
        ) -> (
            dict
            or
            ...
            ):
            
            '''
            self.get_channel_all_members(...)
            '''

            return (
                GetData.api(
                    version     =   self.api_version or '5',
                    method      =   'getChannelAllMembers',
                    auth        =   self.auth,
                    data        =   {
                        'channel_guid'  :   chat_id,
                        'search_text'   :   search_text,
                        'start_id'      :   start_id
                        },
                    mode        =   self.city,
                    proxy       =   self.proxy,
                    platform    =   self.platform or 'web'
                )
            )
    
    def set_channel_action(
        self    :   Client,
        chat_id :   str,
        action  :   str =   'Join'
        ) -> (
            dict or ...
            ):

            '''
            this method for join and leave channels
            
            USE:
                self.set_action_chat('chat-guid', 'Pin')
            PARAMS:
                1- self is a self object
                2- chat_id is chat guid
                3- action is a action type. actions: 'Join', 'Leave'
            '''

            return (
                GetData.api(
                    version     =   self.api_version or '5',
                    auth        =   self.auth,
                    method      =   'joinChannelAction',
                    data        =   {
                        'channel_guid'   :   chat_id,
                        'action'        :   action
                        },
                    mode        =   self.city,
                    platform    =   self.platfrom or 'web',
                    proxy       =   self.proxy
                )
            )

    def add_channel(
        self            : Client,
        title           : str,
        description     : str,
        channel_type    : str   =   'Public'
        ) -> (
            dict or ...
            ):
            
            '''
            this method for create channel
            
            USE:
                self.add_channel('title', 'bio')
            PARAMS:
                1- self is a self object
                2- title is channel name
                3- description is channel bio
                4- channel_type is a action type for channel. types: 'Public', 'Private'
            '''
            
            return (
                GetData.api(
                    version     =   self.api_version or '5',
                    auth        =   self.auth,
                    method      =   'addChannel',
                    data        =   {
                        'title'         :   title,
                        'description'   :   description,
                        'channel_type'  :   channel_type
                        },
                    mode        =   self.city,
                    platform    =   self.platfrom or 'web',
                    proxy       =   self.proxy
                )
            )

    def edit_channnel_info(
        self    :   Client,
        chat_id :   str,
        **kwargs:   dict or str
        ) -> (
            dict or ...
            ):

            '''
            USE:
                self.edit_channnel_info('chat-guid', title='name')
            PARAMS:
                sign_messages, title, description
            '''

            return (
                GetData.api(
                    version     =   self.api_version or '5',
                    auth        =   self.auth,
                    method      =   'editChannelInfo',
                    data        =   {
                        'updated_parameters'        :   list(kwargs.keys())
                        }.update(kwargs),
                    mode        =   self.city,
                    platform    =   self.platfrom or 'web',
                    proxy       =   self.proxy
                )
            )

    def update_channel_username(
        self    :   Client,
        chat_id :   str,
        username:   str
        ) -> (
            dict or ...
            ):
            
            '''
            self.update_channel_username('channel-guid', 'username')
            '''
            
            return (
                GetData.api(
                    version     =   self.api_version or '5',
                    auth        =   self.auth,
                    method      =   'updateChannelUsername',
                    data        =   {
                        'channel_guid'  :   chat_id,
                        'username'      :   username
                        },
                    mode        =   self.city,
                    platform    =   self.platfrom or 'web',
                    proxy       =   self.proxy
                )
            )

    def set_channel_admin(self: Client, chat_id: str, member_guid: str,
                          access_list: list = None, action: str = 'SetAdmin') -> (dict or ...):
        
        '''
        this method is for admin and unadmin a member chat
        
        
        USE:
            self.set_channel_admin('group-guid', 'user-guid', [accesses.admin.sendMessages])
        
        PARAMS:
            1- self a is self object
            2- chat_id is group guid
            3- member_guid is a user guid
            4- access_list is for access user in group: from rub import accesses.admin or ["ChangeInfo", "ViewMembers", "ViewAdmins", "PinMessages", "SendMessages", "EditAllMessages", "DeleteGlobalAllMessages", "AddMember", "SetJoinLink"]
            5- action is action type: 'UnsetAdmin', 'SetAdmin'
        '''
        
        return (
                GetData.api(
                    version     =   self.api_version or '5',
                    auth        =   self.auth,
                    method      =   'setChannelAdmin',
                    data        =   {
                        'channel_guid'  :   chat_id,
                        'member_guid'   :   member_guid,
                        'action'        :   action,
                        'access_list'   :   access_list
                        },
                    mode        =   self.city,
                    platform    =   self.platfrom or 'web',
                    proxy       =   self.proxy
                )
            )

    def channel_preview_by_join_link(self: Client, link: str) -> (dict):
        
        '''
        get channel info from link
        '''
        
        return (
                GetData.api(
                    version     =   self.api_version or '5',
                    auth        =   self.auth,
                    method      =   'channelPreviewByJoinLink',
                    data        =   {
                        'hash_link' :       str(link.split('/')[-1])
                      },
                    mode        =   self.city,
                    platform    =   self.platfrom or 'web',
                    proxy       =   self.proxy
                )
            )

    def join_channel_by_link(
        self: Client,
        link: str
        ) -> (dict):
        
        '''
        this method for join channel with link
        '''
        
        return (
                GetData.api(
                    version     =   self.api_version or '4',
                    auth        =   self.auth,
                    method      =   'joinChannelByLink',
                    data        =   {
                        'hash_link'     :   link.split('/')[-1]
                        },
                    mode        =   self.city,
                    platform    =   self.platfrom or 'android',
                    proxy       =   self.proxy
                )
            )

class WebSocket(
    object,
    ):

    data: dict = {
        'error'     :   [],
        'message'  :   []
        }

    def __init__(
        self,
        session_id
        ) -> ...:
        self.auth: str = session_id
        self.enc: Encryption = Encryption(
            session_id
            )

    def __enter__(
        self
        ) -> ...:
        return self

    def __exit__(
        self,
        *args,
        **kwargs
        ) -> ...:
        pass

    def on_open(self, ws, api_version='5') -> None :
        def handShake(*args):
            ws.send(
                dumps(
                    {
                        'api_version'   :   api_version,
                        'auth'          :   self.auth,
                        'method'        :   'handShake'
                        }
                    )
                )
        import _thread
        _thread.start_new_thread(
            handShake,
            ()
            )

    def on_error(
        self,
        error
        ) -> ...:
        WebSocket.data[
            'error'
            ].append(
                error
                )

    def on_message(
        self,
        message
        ) -> ...:
        try:

            parsedMessage = loads(message)
            WebSocket.data[
                'messages'
                ].append(
                    {
                        'type'  :   parsedMessage[
                            "type"
                            ],
                        'data'  :   loads(
                            self.enc.decrypt(
                                parsedMessage[
                                    "data_enc"
                                    ]
                                )
                            )
                        }
                    )

        except KeyError:
            pass
    
    def on_close(
        self,
        code,
        msg
        ) -> ...:

        return {
            'code': code,
            'message': msg
            }

    def handle(
        self,
        OnOpen=None,
        OnError=None,
        OnMessage=None,
        OnClose=None,
        forEver=True
        ) -> ...:
        from websocket import WebSocketApp
        ws: WebSocketApp = WebSocketApp (
            'wss://jsocket3.iranlms.ir:80',
            on_open=OnOpen or WebSocket(
                self.auth
                ).on_open,
            on_message=OnMessage or WebSocket(
                self.auth
                ).on_message,
            on_error=OnError or WebSocket(
                self.auth
                ).on_error,
            on_close=OnClose or WebSocket(
                self.auth
                ).on_close
            )

        if forEver:
            ws.run_forever()

class RubinoClient(
    clients,
    object):

    def __init__(
        self, session: str
        ) -> ...:
        
        from requests import session as sn
        self.session: sn = sn()
        self.auth: str = session

    def post(
        self,
        json: dict
        ) -> dict:
        for i in range(
            5
            ):
            with self.session.post(
                url=self.url,
                json=json
                ) as res:
                if res.status_code != 200:
                    continue
                else:
                    return res.json()
                    break
    
    def __enter__(
        self
        ) -> ...:
        return self

    def __exit__(
        self,
        *args,
        **kwargs
        ) -> ...: (
            ...
        )

    def makeJson(
        self,
        method: str,
        data: dict
        ) -> str:
        json: dict[str, ] = {
            'api_version':'0',
            'auth':self.auth,
            'client':self.client,
            'data':data,
            'method':method
            }
        return (
            json
            )

    def getProfileList(
        self,
        limit: int = 10,
        sort: str = 'FromMax',
        equal: bool = False
        ) -> dict:
        json = self.makeJson(
            'getProfileList',
            {
                'equal': equal,
                'limit':limit,
                'sort':sort,
                }
        )
        return self.post(
            json
            )

    def follow(
        self,
        followee_id: str,
        profile_id: str
        ) -> dict:
        json = self.makeJson(
            'requestFollow',
            {
            'f_type':'Follow',
            'followee_id':followee_id,
            'profile_id':profile_id
            }
            )
        return self.post(
            json=json
            )

    def unfollow(
        self,
        followee_id: str,
        profile_id: str
        ) -> dict:
        json = self.makeJson(
            'requestFollow',
            {
            'f_type':'Unfollow',
            'followee_id':followee_id,
            'profile_id':profile_id
            }
            )
        return self.post(
            json=json
            )

    def createPage(
        self, **kwargs
        ) -> dict:
        
        '''
        createPage(bio='', name='', username='', email='')
        '''
        
        json = self.makeJson(
            'createPage',
            {
                **kwargs
                }
            )
        return self.post(
            json=json
            )

    def updateProfile(
        self, **kwargs
        ) -> dict:
        ''' updateProfile(bio='', name='', username='', email='')'''
        json = self.makeJson(
            'updateProfile',
            {
                **kwargs
                }
            )
        return self.post(
            json=json
            )

    def isExistUsername(
        self,
        username: str
        ) -> dict:
        json = self.makeJson(
            'isExistUsername',
            {
            'username':username.replace('@','')
            }
            )
        return self.post(
            json=json
            )

    def getPostByShareLink(
        self,
        share_link: str,
        profile_id: str
        ) -> dict:
        json = self.makeJson(
            'getPostByShareLink',
            {
            'share_string':share_link,
            'profile_id':profile_id
            }
            )
        return self.post(
            json=json
            )

    def addComment(
        self,
        text: str,
        post_id: str,
        post_profile_id: str,
        profile_id: str
        ) -> dict:
        json = self.makeJson(
            'addComment',
            {
            'content':text,
            'post_id':post_id,
            'post_profile_id':post_profile_id,
            'rnd':randint(1111111111, 9999999999),
            'profile_id':profile_id
            }
            )
        return self.post(
            json=json
            )

    def likePostAction(
        self,
        post_id: str,
        post_profile_id: str,
        profile_id: str
        ) -> dict:
        json = self.makeJson(
            'likePostAction',
            {
            'action_type':'Like',
            'post_id':post_id,
            'post_profile_id':post_profile_id,
            'profile_id':profile_id
            }
            )
        return self.post(
            json=json
            )

    def unlike(
        self,
        post_id: str,
        post_profile_id: str,
        profile_id: str
        ) -> dict:
        json = self.makeJson(
            'likePostAction',
            {
            'action_type':'Unlike',
            'post_id':post_id,
            'post_profile_id':post_profile_id,
            'profile_id':profile_id
            }
            )
        return self.post(
            json=json
            )

    def addPostViewCount(
        self,
        post_id: str,
        post_profile_id: str
        ) -> dict:
        json = self.makeJson(
            'addPostViewCount',
            {
            'post_id':post_id,
            'post_profile_id':post_profile_id
            }
            )
        return self.post(
            json=json
            )

    def getComments(self,
        post_id: str,
        profile_id: str,
        post_profile_id: str,
        limit: int=50,
        sort: str='FromMax',
        equal: bool=False
        ) -> dict:
        json = self.makeJson(
            'getComments',
            {
            'equal':equal,
            'limit':limit,
            'sort':sort,
            'post_id':post_id,
            'profile_id':profile_id,
            'post_profile_id':post_profile_id
            }
            )
        return self.post(
            json=json
            )

    def getRecentFollowingPosts(self, profile_id: str, limit: int=30,
        sort: str='FromMax',
        equal: bool=False
        ) -> dict:
        json = self.makeJson(
            'getRecentFollowingPosts',
            {
            'equal':equal,
            'limit':limit,
            'sort':sort,
            'profile_id':profile_id
            }
            )
        return self.post(
            json=json
            )

    def getProfilePosts(self,
        target_profile_id: str,
        profile_id: str,
        limit: int=50,
        sort: str='FromMax',
        equal: bool=False
        ) -> dict:
        json = self.makeJson(
            'getRecentFollowingPosts',
            {
            'equal':equal,
            'limit':limit,
            'sort':sort,
            'profile_id':profile_id,
            'target_profile_id':target_profile_id
            }
            )
        return self.post(
            json=json
            )

    def getProfileStories(self,
                          target_profile_id: str,
                          limit: int = 100
                          ) -> dict:
        json = self.makeJson(
            'getProfileStories',
            {
            'limit':limit,
            'profile_id':target_profile_id
            }
            )
        return self.post(
            json=json
            )

class StartClient(
    RubikaClient,
    UserMethods,
    GroupMethods,
    ChannelMethods
    ): # TODO: add all methods
    pass