from ApiMethod import ApiMethod
from typing import List, Union, Dict
from vk_objects import User


class Friends(ApiMethod):
    def __init__(self, access_token, v, session, calls_per_second):
        super(Friends, self).__init__(access_token, v, session, calls_per_second)
        self._base_method = 'friends.'

    def add(self, user_id: str = None, text: str = None, follow: str = None) -> dict:
        """
        Одобряет или создает заявку на добавление в друзья.

        :param user_id: идентификатор пользователя, которому необходимо отправить заявку, либо заявку от которого
            необходимо одобрить.
        :param text: текст сопроводительного сообщения для заявки на добавление в друзья. Максимальная длина
            сообщения — 500 символов.
        :param follow: 1, если необходимо отклонить входящую заявку (оставить пользователя в подписчиках).

        :return: После успешного выполнения возвращает одно из следующих значений:   1 — заявка на добавление
            данного пользователя в друзья отправлена;  2 — заявка на добавление в друзья от данного пользователя
            одобрена;  4 — повторная отправка заявки
        """

        params = locals()
        method_name = self._base_method + 'add'
        return self._call(method_name, params)

    def addList(self, name: str = None, user_ids: str = None) -> dict:
        """
        Создает новый список друзей у текущего пользователя.

        :param name: название создаваемого списка друзей.
        :param user_ids: идентификаторы пользователей, которых необходимо поместить в созданный список.

        :return: После успешного выполнения возвращает идентификатор (list_id) созданного списка друзей
        """

        params = locals()
        method_name = self._base_method + 'addList'
        return self._call(method_name, params)

    def areFriends(self, user_ids: str = None, need_sign: str = None) -> dict:
        """
        Возвращает информацию о том, добавлен ли текущий пользователь в друзья у указанных пользователей.

        :param user_ids: идентификаторы пользователей, статус дружбы с которыми нужно проверить.
        :param need_sign: 1 – необходимо вернуть поле sign которое равно:
            md5("{id}_{user_id}_{friends_status}_{application_secret}"), где id - это идентификатор пользователя, для
            которого выполняется запрос.  и позволяет на сервере убедиться что данные не были подделаны на клиенте.
            0 – поле sign возвращать не нужно.

        :return: После успешного выполнения возвращает массив объектов, каждый из которых содержит следующие
            поля:   user_id — идентификатор пользователя (из числа переданных в параметре user_ids);  friend_status —
            статус дружбы с пользователем:   0 – пользователь не является другом,  1 – отправлена заявка/подписка
            пользователю,  2 – имеется входящая заявка/подписка от пользователя,  3 – пользователь является другом;
            request_message — текст сообщения, прикрепленного к заявке в друзья (если есть).  read_state — статус
            заявки (0 — не просмотрена, 1 — просмотрена), возвращается только если friend_status = 2
        """

        params = locals()
        method_name = self._base_method + 'areFriends'
        return self._call(method_name, params)

    def delete(self, user_id: str = None) -> dict:
        """
        Удаляет пользователя из списка друзей или отклоняет заявку в друзья.

        :param user_id: идентификатор пользователя, которого необходимо удалить из списка друзей, либо заявку от
            которого необходимо отклонить.

        :return: После успешного выполнения начиная с версии 5.28 возвращается объект с полями:   success —
            удалось успешно удалить друга  friend_deleted — был удален друг  out_request_deleted — отменена исходящая
            заявка  in_request_deleted — отклонена входящая заявка  suggestion_deleted — отклонена рекомендация друга
            Для версии 5.27 и более старых возвращает одно из следующих значений:   1 — пользователь удален из списка
            друзей;  2 — заявка на добавление в друзья данного пользователя отклонена (входящая или исходящая);  3 —
            рекомендация добавить в друзья данного пользователя удалена
        """

        params = locals()
        method_name = self._base_method + 'delete'
        return self._call(method_name, params)

    def deleteAllRequests(self) -> dict:
        """
        Отмечает все входящие заявки на добавление в друзья как просмотренные.

        :return: После успешного выполнения возвращает 1
        """

        params = locals()
        method_name = self._base_method + 'deleteAllRequests'
        return self._call(method_name, params)

    def deleteList(self, list_id: str = None) -> dict:
        """
        Удаляет существующий список друзей текущего пользователя.

        :param list_id: идентификатор списка друзей, который необходимо удалить.

        :return: После успешного выполнения возвращает 1
        """

        params = locals()
        method_name = self._base_method + 'deleteList'
        return self._call(method_name, params)

    def edit(self, user_id: str = None, list_ids: str = None) -> dict:
        """
        Редактирует списки друзей для выбранного друга.

        :param user_id: идентификатор пользователя (из числа друзей), для которого необходимо отредактировать
            списки друзей.
        :param list_ids: идентификаторы списков друзей, в которые нужно добавить пользователя.

        :return: После успешного выполнения возвращает 1
        """

        params = locals()
        method_name = self._base_method + 'edit'
        return self._call(method_name, params)

    def editList(self, name: str = None, list_id: str = None, user_ids: str = None, add_user_ids: str = None,
                 delete_user_ids: str = None) -> dict:
        """
        Редактирует существующий список друзей текущего пользователя.

        :param name: название списка друзей.
        :param list_id: идентификатор списка друзей.
        :param user_ids: идентификаторы пользователей, включенных в список.
        :param add_user_ids: идентификаторы пользователей, которых необходимо добавить в список. (в случае если
            не передан user_ids)
        :param delete_user_ids: идентификаторы пользователей, которых необходимо изъять из списка. (в случае если
            не передан user_ids)

        :return: После успешного выполнения возвращает 1
        """

        params = locals()
        method_name = self._base_method + 'editList'
        return self._call(method_name, params)

    def get(self, user_id: str = None, order: str = None, list_id: str = None, count: str = None, offset: str = None,
            fields: str = None, name_case: str = None, ref: str = None) -> dict:
        """
        Возвращает список идентификаторов друзей пользователя или расширенную информацию о друзьях пользователя (при
        использовании параметра fields).

        :param user_id: идентификатор пользователя, для которого необходимо получить список друзей. Если параметр
            не задан, то считается, что он равен идентификатору текущего пользователя (справедливо для вызова с
            передачей access_token).
        :param order: порядок, в котором нужно вернуть список друзей. Допустимые значения:   hints — сортировать
            по рейтингу, аналогично тому, как друзья сортируются в разделе Мои друзья (Это значение доступно только
            для Standalone-приложений с ключом доступа, полученным по схеме Implicit Flow.).  random — возвращает
            друзей в случайном порядке.  mobile — возвращает выше тех друзей, у которых установлены мобильные
            приложения.  name — сортировать по имени. Данный тип сортировки работает медленно, так как сервер будет
            получать всех друзей а не только указанное количество count. (работает только при переданном параметре
            fields).   По умолчанию список сортируется в порядке возрастания идентификаторов пользователей.
        :param list_id: идентификатор списка друзей, полученный методом friends.getLists, друзей из которого
            необходимо получить. Данный параметр учитывается, только когда параметр user_id равен идентификатору
            текущего пользователя.  Этот параметр доступен только для Standalone-приложений с ключом доступа,
            полученным по схеме Implicit Flow.
        :param count: количество друзей, которое нужно вернуть.
        :param offset: смещение, необходимое для выборки определенного подмножества друзей.
        :param fields: список дополнительных полей, которые необходимо вернуть.  Доступные значения: nickname,
            domain, sex, bdate, city, country, timezone, photo_50, photo_100, photo_200_orig, has_mobile, contacts,
            education, online, relation, last_seen, status, can_write_private_message, can_see_all_posts, can_post,
            universities
        :param name_case: падеж для склонения имени и фамилии пользователя. Возможные значения: именительный –
            nom, родительный – gen, дательный – dat, винительный – acc, творительный – ins, предложный – abl. По
            умолчанию nom.
        :param ref:

        :return: После успешного выполнения возвращает список идентификаторов (id) друзей пользователя, если
            параметр fields не использовался.  При использовании параметра fields возвращает список объектов
            пользователей, но не более 5000
        """

        params = locals()
        method_name = self._base_method + 'get'
        return self._call(method_name, params)

    def getAppUsers(self) -> dict:
        """
        Возвращает список идентификаторов друзей текущего пользователя, которые установили данное приложение.

        :return: После успешного выполнения возвращает список идентификаторов (id) друзей текущего пользователя,
            установивших приложение
        """

        params = locals()
        method_name = self._base_method + 'getAppUsers'
        return self._call(method_name, params)

    def getByPhones(self, phones: str = None, fields: str = None) -> dict:
        """
        Возвращает список друзей пользователя, у которых завалидированные или указанные в профиле телефонные номера
        входят в заданный список.

        :param phones: список телефонных номеров в формате MSISDN, разделеннных запятыми. Например
            +79219876543,+79111234567 Максимальное количество номеров в списке — 1000.
        :param fields: список дополнительных полей, которые необходимо вернуть.  Доступные значения: nickname,
            screen_name, sex, bdate, city, country, timezone, photo_50, photo_100, photo_200_orig, has_mobile,
            contacts, education, online, counters, relation, last_seen, status, can_write_private_message,
            can_see_all_posts, can_post, universities.

        :return: После успешного выполнения возвращает список объектов пользователей с дополнительным полем
            phone, в котором содержится номер из списка заданных для поиска номеров
        """

        params = locals()
        method_name = self._base_method + 'getByPhones'
        return self._call(method_name, params)

    def getLists(self, user_id: str = None, return_system: str = None) -> dict:
        """
        Возвращает список меток друзей пользователя.

        :param user_id: идентификатор пользователя.
        :param return_system: возвращать ли системный список публичных меток друзей пользователя.

        :return: После успешного выполнения возвращает список объектов, каждый из которых содержит следующие
            поля:   name — название списка друзей;  id — идентификатор списка друзей
        """

        params = locals()
        method_name = self._base_method + 'getLists'
        return self._call(method_name, params)

    def getMutual(self, source_uid: str = None, target_uid: str = None, target_uids: str = None, order: str = None,
                  count: str = None, offset: str = None) -> dict:
        """
        Возвращает список идентификаторов общих друзей между парой пользователей.

        :param source_uid: идентификатор пользователя, чьи друзья пересекаются с друзьями пользователя с
            идентификатором target_uid. Если параметр не задан, то считается, что source_uid равен идентификатору
            текущего пользователя.
        :param target_uid: идентификатор пользователя, с которым необходимо искать общих друзей.
        :param target_uids: список идентификаторов пользователей, с которыми необходимо искать общих друзей.
        :param order: порядок, в котором нужно вернуть список общих друзей. Допустимые значения: random -
            возвращает друзей в случайном порядке. По умолчанию — в порядке возрастания идентификаторов.
        :param count: количество общих друзей, которое нужно вернуть. (по умолчанию – все общие друзья)
        :param offset: смещение, необходимое для выборки определенного подмножества общих друзей.

        :return: После успешного выполнения возвращает список идентификаторов (id) общих друзей между
            пользователями с идентификаторами source_uid и target_uid
        """

        params = locals()
        method_name = self._base_method + 'getMutual'
        return self._call(method_name, params)

    def getOnline(self, user_id: str = None, list_id: str = None, online_mobile: str = None, order: str = None,
                  count: str = None, offset: str = None) -> dict:
        """
        Возвращает список идентификаторов друзей пользователя, находящихся на сайте.

        :param user_id: идентификатор пользователя, для которого необходимо получить список друзей онлайн. Если
            параметр не задан, то считается, что он равен идентификатору текущего пользователя.
        :param list_id: идентификатор списка друзей. Если параметр не задан, возвращается информация обо всех
            друзьях, находящихся на сайте.
        :param online_mobile: 1 — будет возвращено дополнительное поле online_mobile.  По умолчанию — 0.
        :param order: порядок, в котором нужно вернуть список друзей, находящихся на сайте. Допустимые значения:
            random - возвращает друзей в случайном порядке, hints - сортировать по рейтингу, аналогично тому, как
            друзья сортируются в разделе Мои друзья (данный параметр доступен только для Desktop-приложений).  По
            умолчанию список сортируется в порядке возрастания идентификаторов пользователей.
        :param count: количество друзей онлайн, которое нужно вернуть. (по умолчанию – все друзья онлайн)
        :param offset: смещение, необходимое для выборки определенного подмножества друзей онлайн.

        :return: После успешного выполнения возвращает список идентификаторов (id) друзей, находящихся сейчас на
            сайте, у пользователя с идентификатором uid и входящих в список с идентификатором lid.  При использовании
            параметра online_mobile=1 также возвращается поле online_mobile, содержащее список идентификатор друзей,
            находящихся на сайте с мобильного устройства
        """

        params = locals()
        method_name = self._base_method + 'getOnline'
        return self._call(method_name, params)

    def getRecent(self, count: str = None) -> dict:
        """
        Возвращает список идентификаторов недавно добавленных друзей текущего пользователя.

        :param count: максимальное количество недавно добавленных друзей, которое необходимо получить.

        :return: После успешного выполнения возвращает отсортированный в антихронологическом порядке список
            идентификаторов (id) недавно добавленных друзей текущего пользователя
        """

        params = locals()
        method_name = self._base_method + 'getRecent'
        return self._call(method_name, params)

    def getRequests(self, offset: str = None, count: str = None, extended: str = None, need_mutual: str = None,
                    out: str = None, sort: str = None, need_viewed: str = None, suggested: str = None, ref: str = None,
                    fields: str = None) -> dict:
        """
        Возвращает информацию о полученных или отправленных заявках на добавление в друзья для текущего пользователя.

        :param offset: смещение, необходимое для выборки определенного подмножества заявок на добавление в
            друзья.
        :param count: максимальное количество заявок на добавление в друзья, которые необходимо получить (не
            более 1000).  По умолчанию — 100.
        :param extended: определяет, требуется ли возвращать в ответе сообщения от пользователей, подавших заявку
            на добавление в друзья. И отправителя рекомендации при suggested = 1.
        :param need_mutual: определяет, требуется ли возвращать в ответе список общих друзей, если они есть.
            Обратите внимание, что при использовании need_mutual будет возвращено не более 2 заявок.
        :param out: 0 — возвращать полученные заявки в друзья (по умолчанию), 1 — возвращать отправленные
            пользователем заявки.
        :param sort: 0 — сортировать по дате добавления, 1 — сортировать по количеству общих друзей. (Если out =
            1, этот параметр не учитывается).
        :param need_viewed: 0 - не возвращать просмотренные заявки, 1 — возвращать просмотренные заявки. (Если
            out = 1, данный параметр не учитывается).
        :param suggested: 1 — возвращать рекомендованных другими пользователями друзей, 0 — возвращать заявки в
            друзья (по умолчанию).
        :param ref:
        :param fields:

        :return:   Если не установлен параметр need_mutual, то в случае успеха возвращает отсортированный в
            антихронологическом порядке по времени подачи заявки список идентификаторов (id) пользователей (кому или
            от кого пришла заявка).     Если установлен параметр need_mutual, то в случае успеха возвращает
            отсортированный в антихронологическом порядке по времени подачи заявки массив объектов, содержащих
            информацию о заявках на добавление в друзья. Каждый из объектов содержит поле uid, являющийся
            идентификатором пользователя. При наличии общих друзей, в объекте будет содержаться поле mutual, в
            котором будет находиться список идентификаторов общих друзей
        """

        params = locals()
        method_name = self._base_method + 'getRequests'
        return self._call(method_name, params)

    def getSuggestions(self, filter: str = None, count: str = None, offset: str = None, fields: str = None,
                       name_case: str = None) -> dict:
        """
        Возвращает список профилей пользователей, которые могут быть друзьями текущего пользователя.

        :param filter: типы предлагаемых друзей, которые нужно вернуть, перечисленные через запятую.  Может
            принимать следующие значения:  mutual — пользователи, с которыми много общих друзей; По умолчанию будут
            возвращены все возможные друзья.
        :param count: количество рекомендаций, которое необходимо вернуть.
        :param offset: смещение, необходимое для выбора определённого подмножества списка.
        :param fields: список дополнительных полей, которые необходимо вернуть.  Доступные значения: nickname,
            screen_name, sex, bdate, city, country, timezone, photo_50, photo_100, photo_200_orig, has_mobile,
            contacts, education, online, counters, relation, last_seen, status, can_write_private_message,
            can_see_all_posts, can_post, universities
        :param name_case: падеж для склонения имени и фамилии пользователя. Возможные значения: именительный –
            nom, родительный – gen, дательный – dat, винительный – acc, творительный – ins, предложный – abl. По
            умолчанию nom.

        :return: После успешного выполнения возвращает список объектов пользователей с дополнительным полем
            found_with для пользователей, найденных через импорт контактов. Для некоторых пользователей, которые были
            найдены давно поле found_with может отсутствовать
        """

        params = locals()
        method_name = self._base_method + 'getSuggestions'
        return self._call(method_name, params)

    def search(self, user_id: str = None, q: str = None, fields: str = None, name_case: str = None, offset: str = None,
               count: str = None) -> dict:
        """
        Позволяет искать по списку друзей пользователей.

        :param user_id: идентификатор пользователя, по списку друзей которого необходимо произвести поиск.
        :param q:  запроса.
        :param fields: список дополнительных полей, которые необходимо вернуть.  Доступные значения: nickname,
            screen_name, sex, bdate, city, country, timezone, photo_50, photo_100, photo_200_orig, has_mobile,
            contacts, education, online, relation, last_seen, status, can_write_private_message, can_see_all_posts,
            can_post, universities, domain
        :param name_case: падеж для склонения имени и фамилии пользователя. Возможные значения: именительный –
            nom, родительный – gen, дательный – dat, винительный – acc, творительный – ins, предложный – abl. По
            умолчанию nom.
        :param offset: смещение, необходимое для выборки определенного подмножества друзей.
        :param count: количество друзей, которое нужно вернуть.

        :return: После успешного выполнения метод возвращает список объектов пользователей
        """

        params = locals()
        method_name = self._base_method + 'search'
        return self._call(method_name, params)
