# Generated by the protocol buffer compiler.  DO NOT EDIT!
# sources: keyapis/banner/v1/keyapis_banner_banner_v1.proto, keyapis/banner/v1/keyapis_banner_system_v1.proto
# plugin: python-betterproto
# This file has been @generated

from collections.abc import AsyncIterator
from datetime import datetime
from typing import TYPE_CHECKING

import betterproto
import grpclib
from betterproto.grpc.grpclib_server import ServiceBase
from pydantic import model_validator
from pydantic.dataclasses import (
    dataclass,
    rebuild_dataclass,
)

if TYPE_CHECKING:
    import grpclib.server
    from betterproto.grpc.grpclib_client import MetadataLike
    from grpclib.metadata import Deadline


class BannerType(betterproto.Enum):
    """
    Справочник типов баннеров.
     # Тип: byte
    """

    TYPE_UNKNOWN = 0
    """Значение не указано"""

    STANDARD = 1
    """Стандартный баннер"""

    @classmethod
    def __get_pydantic_core_schema__(cls, _source_type, _handler):
        from pydantic_core import core_schema

        return core_schema.int_schema(ge=0)


class BannerPriorityType(betterproto.Enum):
    """
    Справочник типов приоритетов.
     # Тип: byte
    """

    PRIORITY_TYPE_UNKNOWN = 0
    """Значение не указано"""

    NORMAL = 1
    """
    Обычный.
     Приоритет 31.
     Вычисляется в логике приложения как priority меньше 64.
     Извлекаются из базы по фильтру end_priority = 64
    """

    WHITE_LABEL = 2
    """
    Вайт-лейбл.
     Приоритет 127.
     Вычисляется в логике приложения как priority больше или равно 64 и priority меньше 160.
     Извлекаются из базы по фильтру begin_priority = 64 и end_priority = 160
    """

    CRITICAL = 3
    """
    Критикл.
     Приоритет 191.
     Вычисляется в логике приложения как priority больше или равно 160.
     Извлекаются из базы по фильтру begin_priority = 160
    """

    @classmethod
    def __get_pydantic_core_schema__(cls, _source_type, _handler):
        from pydantic_core import core_schema

        return core_schema.int_schema(ge=0)


class BannerStatusType(betterproto.Enum):
    """
    Справочник статусов баннеров.
     # Тип: byte
    """

    STATUS_TYPE_UNKNOWN = 0
    """Значение не указано"""

    DEFERRED = 1
    """
    Отложен.
     Вычисляется в логике приложения как сurr_date меньше show_start_at.
     Извлекаются из базы по фильтру end_show_start_at = сurr_date
    """

    ACTIVE = 2
    """
    Активен.
     Вычисляется в логике приложения как сurr_date больше или равно show_start_at и сurr_date меньше show_ended_at.
     Извлекаются из базы по фильтру begin_show_start_at = сurr_date и end_show_ended_at = сurr_date
    """

    EXPIRED = 3
    """
    Истёк.
     Вычисляется в логике приложения как сurr_date больше или равно show_ended_at.
     Извлекаются из базы по фильтру begin_show_ended_at = сurr_date
    """

    @classmethod
    def __get_pydantic_core_schema__(cls, _source_type, _handler):
        from pydantic_core import core_schema

        return core_schema.int_schema(ge=0)


class BannerPlatformType(betterproto.Enum):
    """
    Справочник платформ.
     # Тип: byte
    """

    PLATFORM_TYPE_UNKNOWN = 0
    """Значение не указано"""

    IOS = 1
    """
    Платформа iOS.
     Приложение размещается в App Store
    """

    ANDROID = 2
    """
    Платформа Android.
     Приложение размещается в Google Play, App Gallery или прочих сторах
    """

    WEB = 3
    """
    Платформа Web.
     Приложение размещается по интернет адресу
    """

    @classmethod
    def __get_pydantic_core_schema__(cls, _source_type, _handler):
        from pydantic_core import core_schema

        return core_schema.int_schema(ge=0)


class BannerImageType(betterproto.Enum):
    """
    Справочник типов картинок.
     # Тип: byte
    """

    TYPE_UNKNOWN = 0
    """Значение не указано"""

    PORTRAIT = 1
    """
    Пререндеренный баннер в портретном режиме.
     В портретном режиме ширина меньше или равна высоте.
     Представление характерно для телефонов.
     Может содержать дополнительные параметры запроса в ссылке(https://docs.imgproxy.net/generating_the_url?id=processing-options).
     После загрузки изображения отрисовывается поверх цвета и градиента.
     Если ссылки нет то нужно использовать ссылку из ландшафтного режима
    """

    LANDSCAPE = 2
    """
    Пререндеренный баннер в ландшафтном режиме.
     В ландшафтном режиме ширина больше высоты.
     Представление характерно для планшетов и декстопа.
     Может содержать дополнительные параметры запроса в ссылке(https://docs.imgproxy.net/generating_the_url?id=processing-options).
     После загрузки изображения отрисовывается поверх цвета и градиента.
     Если ссылки нет то нужно использовать ссылку из портретного режима
    """

    ICON = 3
    """
    Иконка.
     Может содержать дополнительные параметры запроса в ссылке(https://docs.imgproxy.net/generating_the_url?id=processing-options).
     После загрузки изображения отрисовывается поверх цвета и градиента
    """

    @classmethod
    def __get_pydantic_core_schema__(cls, _source_type, _handler):
        from pydantic_core import core_schema

        return core_schema.int_schema(ge=0)


class BannerLinkType(betterproto.Enum):
    """
    Справочник типов ссылок.
     # Тип: byte
    """

    TYPE_UNKNOWN = 0
    """Значение не указано"""

    INTERNAL_APP = 1
    """Ссылка для перехода на раздел текущего приложения"""

    EXTERNAL_APP = 2
    """Ссылка для перехода на стороннее приложение"""

    WEB_VIEW = 3
    """
    Ссылка для перехода на веб-вью внутренних (своих) приложений.
     В окне отсутствует адресаная строка.
     Для iOS используется WKWebView, для Android используется WebView
    """

    WEB_BROWSER = 4
    """Ссылка для перехода на веб-браузер"""

    EXTERNAL_WEB_VIEW = 5
    """
    Ссылка для перехода на веб-вью внешних (партнёрских) приложений.
     В окне присутствует адресаная строка.
     Для iOS используется SFSafariViewController, для Android используется ChromeCustomTabs
    """

    @classmethod
    def __get_pydantic_core_schema__(cls, _source_type, _handler):
        from pydantic_core import core_schema

        return core_schema.int_schema(ge=0)


class BannerPagingOrderByType(betterproto.Enum):
    """
    Справочник типов значений сортировки.
     # Тип: byte
    """

    ORDER_BY_TYPE_UNKNOWN = 0
    """Значение не указано"""

    CHANGED_AT = 1
    """Дата последнего изменения"""

    PRIORITY_THEN_SHOW_START_AT = 2
    """По приоритету, затем по дате начала показа"""

    CREATED_AT = 3
    """Дата создания"""

    SHOW_START_AT = 4
    """Дата начала показа"""

    SHOW_ENDED_AT = 5
    """Дата конца показа"""

    RANK = 6
    """
    По рангу для поиска по тексту.
     Применяется когда передано поле для поиска по тексту.
     В случае если текстовое поле не передано, применяется значение по умолчанию
    """

    @classmethod
    def __get_pydantic_core_schema__(cls, _source_type, _handler):
        from pydantic_core import core_schema

        return core_schema.int_schema(ge=0)


class BannerPagingDirectionType(betterproto.Enum):
    """
    Справочник типов направлений сортировки.
     # Тип: byte
    """

    DIRECTION_TYPE_UNKNOWN = 0
    """Значение не указано"""

    DESC = 1
    """От большего к меньшему"""

    ASC = 2
    """От меньшего к большему"""

    @classmethod
    def __get_pydantic_core_schema__(cls, _source_type, _handler):
        from pydantic_core import core_schema

        return core_schema.int_schema(ge=0)


@dataclass(eq=False, repr=False, config={"extra": "forbid"})
class Banner(betterproto.Message):
    """
    Баннер.
     # Описание модели
    """

    id: str = betterproto.string_field(1)
    """
    Идентификатор.
     Если не передан создаётся сервером.
     # Тип: Guid
    """

    type: "BannerType" = betterproto.enum_field(2)
    """
    Тип баннера.
     Обязательное
    """

    priority: int = betterproto.int32_field(3)
    """
    Приоритет.
     Обязательное.
     # Диапазон: 1..255
    """

    priority_type: "BannerPriorityType" = betterproto.enum_field(4)
    """
    Тип приоритета.
     # Поле вычисляется в коде приложения
    """

    title: str = betterproto.string_field(5)
    """
    Название.
     Обязательное.
     Обычно это название рекламной компании.
     Не отображается пользователям.
     # Диапазон: 3..256
    """

    header: "str | None" = betterproto.message_field(6, wraps=betterproto.TYPE_STRING)
    """
    Заголовок.
     # Диапазон: 3..64
    """

    header_color: "str | None" = betterproto.message_field(
        7, wraps=betterproto.TYPE_STRING
    )
    """
    Цвет текста заголовка.
     Все цвета должны быть в формате hex #RRGGBBAA.
     Пример: #7e00c380.
     # Диапазон: 9..9.
     # Паттерн: /^#[0-9a-fA-F]{8}$/
    """

    subtitle: "str | None" = betterproto.message_field(8, wraps=betterproto.TYPE_STRING)
    """
    Подзаголовок.
     # Диапазон: 3..256
    """

    subtitle_color: "str | None" = betterproto.message_field(
        9, wraps=betterproto.TYPE_STRING
    )
    """
    Цвет текста подзаголовка.
     Все цвета должны быть в формате hex #RRGGBBAA.
     Пример: #7e00c380.
     # Диапазон: 9..9.
     # Паттерн: /^#[0-9a-fA-F]{8}$/
    """

    background_color: "str | None" = betterproto.message_field(
        10, wraps=betterproto.TYPE_STRING
    )
    """
    Цвет заднего плана(подложки).
     Отрисовывается до загрузки картинки и градиента.
     Все цвета должны быть в формате hex #RRGGBBAA.
     Пример: #7e00c380.
     # Диапазон: 9..9.
     # Паттерн: /^#[0-9a-fA-F]{8}$/
    """

    background_gradient: "BannerGradient" = betterproto.message_field(11)
    """Градиент"""

    repeat_after_days: "int | None" = betterproto.message_field(
        12, wraps=betterproto.TYPE_INT32
    )
    """
    Количество дней через которое можно повторно показать баннер.
     Если null, то закрыть нельзя, баннер повторно выводится каждый раз.
     # Диапазон: 0..366
    """

    show_start_at: datetime = betterproto.message_field(13)
    """
    Дата начала показа.
     Обязательное.
     Бессрочно если значение 2000-01-01.
     # Тип: DateOnly.
     # Диапазон: 730119..1095362
    """

    show_ended_at: datetime = betterproto.message_field(14)
    """
    Дата конца показа.
     Обязательное.
     Бессрочно если значение 3000-01-01.
     # Тип: DateOnly.
     # Диапазон: 730119..1095362
    """

    status_type: "BannerStatusType" = betterproto.enum_field(15)
    """
    Статус баннера.
     # Поле вычисляется в коде приложения
    """

    images: "list[BannerImage]" = betterproto.message_field(16)
    """
    Картинки.
     # Диапазон: 0..20
    """

    links: "list[BannerLink]" = betterproto.message_field(17)
    """
    Ссылки для переходов.
     # Диапазон: 0..100
    """

    user_tags: "list[str]" = betterproto.string_field(18)
    """
    Список тегов пользователей.
     Обязательное.
     Описывает кто может видеть баннер.
     Тэг - максимум 5 символов, значение - максимум 19 символов, количество сегментов - максимум 10.
     # Диапазон: 1..100.
     # Паттерн: /^[A-Z-]{1,5}_[0-9A-Z-]{1,19}(?:\.[A-Z-]{1,5}_[0-9A-Z-]{1,19}){0,9}$/
    """

    app_tags: "list[str]" = betterproto.string_field(19)
    """
    Список тегов приложений.
     Обязательное.
     Описывает какие клиенты могут видеть баннер.
     Тэг - максимум 5 символов, значение - максимум 19 символов, количество сегментов - максимум 10.
     # Диапазон: 1..20.
     # Паттерн: /^[A-Z-]{1,5}_[0-9A-Z-]{1,19}(?:\.[A-Z-]{1,5}_[0-9A-Z-]{1,19}){0,9}$/
    """

    created_at: datetime = betterproto.message_field(20)
    """
    Дата создания.
     # Тип: DateTime
    """

    changed_at: datetime = betterproto.message_field(21)
    """
    Дата последнего изменения.
     Заполняется и обновляется сервером.
     Заполняется при создании и изменении.
     Является версией объекта.
     # Тип: DateTime
    """


@dataclass(eq=False, repr=False, config={"extra": "forbid"})
class BannerGradient(betterproto.Message):
    """Градиент"""

    linear: "BannerGradientLinear | None" = betterproto.message_field(
        1, optional=True, group="type"
    )
    """Линейный градиент"""

    @model_validator(mode="after")
    def check_oneof(cls, values):
        return cls._validate_field_groups(values)


@dataclass(eq=False, repr=False, config={"extra": "forbid"})
class BannerGradientLinear(betterproto.Message):
    """Линейный градиент"""

    angle: float = betterproto.float_field(1)
    """
    Угол направления линейного градиента в градусах.
     # Диапазон: 0..360
    """

    points: "list[BannerGradientLinearPoint]" = betterproto.message_field(2)
    """
    Точки градиента.
     Обязательное.
     # Диапазон: 2..20
    """


@dataclass(eq=False, repr=False, config={"extra": "forbid"})
class BannerGradientLinearPoint(betterproto.Message):
    """Точка"""

    color: str = betterproto.string_field(1)
    """
    Цвет линейного градиента.
     Обязательное.
     Отрисовывается до загрузки картинки и градиента.
     Все цвета должны быть в формате hex #RRGGBBAA.
     Пример: #7e00c380.
     # Диапазон: 9..9.
     # Паттерн: /^#[0-9a-fA-F]{8}$/
    """

    stop: float = betterproto.float_field(2)
    """
    Стоп линейного градиента.
     Записывается в процентах.
     # Диапазон: 0..100
    """


@dataclass(eq=False, repr=False, config={"extra": "forbid"})
class BannerImage(betterproto.Message):
    """Объект картинки"""

    type: "BannerImageType" = betterproto.enum_field(1)
    """
    Тип картинки.
     Обязательное
    """

    url: str = betterproto.string_field(2)
    """
    Значение ссылки на картинку.
     Обязательное.
     # Диапазон: 12..512
    """


@dataclass(eq=False, repr=False, config={"extra": "forbid"})
class BannerLink(betterproto.Message):
    """Ссылка"""

    platform_type: "BannerPlatformType" = betterproto.enum_field(1)
    """
    Тип платформы.
     Обязательное
    """

    type: "BannerLinkType" = betterproto.enum_field(2)
    """
    Тип ссылки.
     Обязательное
    """

    url: str = betterproto.string_field(3)
    """
    Значение ссылки для перехода.
     Обязательное.
     # Диапазон: 12..512
    """

    packages: "list[str]" = betterproto.string_field(4)
    """
    Список пакетов.
     Если пусто попытка перехода осуществляется безусловно.
     Если заполнено, то переход осуществляется только в случае если хоть один пакет есть на устройстве, иначе обработка переходит к следующей ссылке.
     # Диапазон: 0..20
    """


@dataclass(eq=False, repr=False, config={"extra": "forbid"})
class BannerSavingError(betterproto.Message):
    """
    Ошибка сохранения.
     Эти проверки выполняются при работе с базой данных и сторонними сервисами
    """

    conflict: "BannerSavingErrorConflict | None" = betterproto.message_field(
        1, optional=True, group="reason"
    )
    """Конфликт версий"""

    @model_validator(mode="after")
    def check_oneof(cls, values):
        return cls._validate_field_groups(values)


@dataclass(eq=False, repr=False, config={"extra": "forbid"})
class BannerSavingErrorConflict(betterproto.Message):
    """
    Конфликт версий.
     Причины:
     - В базе хранится другая версия строки, значения changed_at отличаются
    """

    pass


@dataclass(eq=False, repr=False, config={"extra": "forbid"})
class BannerLite(betterproto.Message):
    """Облегчённый баннер"""

    id: str = betterproto.string_field(1)
    """
    Идентификатор.
     # Тип: Guid
    """

    repeat_after_days: "int | None" = betterproto.message_field(
        2, wraps=betterproto.TYPE_INT32
    )
    """
    Количество дней через которое можно повторно показать баннер.
     Если Значение не указано то повторного показа баннера не будет
    """

    images: "list[BannerLiteImageLite]" = betterproto.message_field(3)
    """Картинки"""

    links: "list[BannerLiteLinkLite]" = betterproto.message_field(4)
    """
    Ссылки для переходов.
     Возвращаются отфильтрованные по платформе
    """


@dataclass(eq=False, repr=False, config={"extra": "forbid"})
class BannerLiteImageLite(betterproto.Message):
    """Упрощённый объект картинки"""

    type: "BannerImageType" = betterproto.enum_field(1)
    """
    Тип картинки.
     Обязательное
    """

    url: str = betterproto.string_field(2)
    """
    Значение ссылки на картинку.
     Обязательное
    """


@dataclass(eq=False, repr=False, config={"extra": "forbid"})
class BannerLiteLinkLite(betterproto.Message):
    """Упрощённая ссылка"""

    type: "BannerLinkType" = betterproto.enum_field(1)
    """
    Тип ссылки.
     Обязательное
    """

    url: str = betterproto.string_field(2)
    """
    Значение ссылки.
     Обязательное
    """

    packages: "list[str]" = betterproto.string_field(3)
    """
    Список пакетов.
     Если пусто попытка перехода осуществляется безусловно.
     Если заполнено, то переход осуществляется только в случае если хоть один пакет есть на устройстве иначе обработка переходит к следующей ссылке
    """

    platform_type: "BannerPlatformType" = betterproto.enum_field(4)
    """
    Тип платформы.
     Обязательное
    """


@dataclass(eq=False, repr=False, config={"extra": "forbid"})
class BannerFilter(betterproto.Message):
    """Фильтр баннеров"""

    text: "str | None" = betterproto.message_field(1, wraps=betterproto.TYPE_STRING)
    """
    По тексту.
     Если значение не передано то поиск по нему не производится.
     # Диапазон: 3..64.
     # Поиск производится по полям:
     # - Название;
     # - Заголовок;
     # - Подзаголовок;
     # - Список тегов пользователей;
     # - Список тегов приложений
    """

    types: "list[BannerType]" = betterproto.enum_field(2)
    """По типам баннеров"""

    begin_priority: "int | None" = betterproto.message_field(
        3, wraps=betterproto.TYPE_INT32
    )
    """От приоритета включительно (больше или равно)"""

    end_priority: "int | None" = betterproto.message_field(
        4, wraps=betterproto.TYPE_INT32
    )
    """До приоритета (меньше)"""

    priority_types: "list[BannerPriorityType]" = betterproto.enum_field(5)
    """
    По типам приоритетов.
     Переписывает значения фильтров по приоритету.
     Если переданы все типы, то фильтр игнорируется(так как нужно вернуть всё)
    """

    begin_show_start_at: datetime = betterproto.message_field(6)
    """От даты начала показа включительно (больше или равно)"""

    end_show_start_at: datetime = betterproto.message_field(7)
    """До даты начала показа (меньше)"""

    begin_show_ended_at: datetime = betterproto.message_field(8)
    """От даты конца показа включительно (больше или равно)"""

    end_show_ended_at: datetime = betterproto.message_field(9)
    """До даты конца показа (меньше)"""

    status_types: "list[BannerStatusType]" = betterproto.enum_field(10)
    """
    По статусам баннеров.
     Переписывает значения фильтров по датам.
     Если переданы все типы, то фильтр игнорируется(так как нужно вернуть всё)
    """

    user_tags: "list[str]" = betterproto.string_field(11)
    """
    По пользовательским тегам.
     Тэг - максимум 5 символов, значение - максимум 19 символов, количество сегментов - максимум 10.
     # Диапазон: 0..20.
     # Паттерн: /^[A-Z-]{1,5}_[0-9A-Z-]{1,19}(?:\.[A-Z-]{1,5}_[0-9A-Z-]{1,19}){0,9}$/
    """

    app_tags: "list[str]" = betterproto.string_field(12)
    """
    По тегам приложений.
     Тэг - максимум 5 символов, значение - максимум 19 символов, количество сегментов - максимум 10.
     # Диапазон: 0..20.
     # Паттерн: /^[A-Z-]{1,5}_[0-9A-Z-]{1,19}(?:\.[A-Z-]{1,5}_[0-9A-Z-]{1,19}){0,9}$/
    """


@dataclass(eq=False, repr=False, config={"extra": "forbid"})
class BannerLiteFilter(betterproto.Message):
    """Упрощённый фильтр по баннерам"""

    types: "list[BannerType]" = betterproto.enum_field(1)
    """По типам баннеров"""

    app_name: "str | None" = betterproto.message_field(2, wraps=betterproto.TYPE_STRING)
    """
    Название приложения.
     # Диапазон: 1..19.
     # Паттерн: /^[0-9A-Z-]{1,19}$/
    """

    platform_type: "BannerPlatformType" = betterproto.enum_field(3)
    """Тип платформы"""

    version: "str | None" = betterproto.message_field(4, wraps=betterproto.TYPE_STRING)
    """
    Версия приложения.
     # Диапазон: 1..19.
     # Паттерн: /^[0-9A-Z-]{1,19}$/
    """

    user_tags: "list[str]" = betterproto.string_field(5)
    """
    По тегам пользователя.
     Тэг - максимум 5 символов, значение - максимум 19 символов, количество сегментов - максимум 10.
     # Диапазон: 1..20.
     # Паттерн: /^[A-Z-]{1,5}_[0-9A-Z-]{1,19}(?:\.[A-Z-]{1,5}_[0-9A-Z-]{1,19}){0,9}$/
    """


@dataclass(eq=False, repr=False, config={"extra": "forbid"})
class BannerPaging(betterproto.Message):
    """Пагинация баннеров"""

    order_by_type: "BannerPagingOrderByType" = betterproto.enum_field(1)
    """
    Тип значения сортировки.
     Если значение не передано, то будет взято значение по умолчанию.
     # По умолчанию: CHANGED_AT
    """

    direction_type: "BannerPagingDirectionType" = betterproto.enum_field(2)
    """
    Тип направления сортировки.
     # По умолчанию: DESC
    """

    limit: int = betterproto.int32_field(3)
    """
    Количество записей на страницу.
     Если значение 0 (не передано), то будет взято значение по умолчанию.
     # Диапазон: 0..100.
     # По умолчанию: 20
    """

    offset: int = betterproto.int32_field(4)
    """
    Сдвиг.
     # Диапазон: 0..2147483647
    """


@dataclass(eq=False, repr=False, config={"extra": "forbid"})
class PostBannerRequest(betterproto.Message):
    """Запрос сохранения баннера"""

    data: "Banner" = betterproto.message_field(1)
    """Баннер"""


@dataclass(eq=False, repr=False, config={"extra": "forbid"})
class PostBannerResponse(betterproto.Message):
    """Ответ на запрос сохранения баннера"""

    data: "Banner | None" = betterproto.message_field(1, optional=True, group="type")
    """Баннер"""

    error: "PostBannerResponseError | None" = betterproto.message_field(
        2, optional=True, group="type"
    )
    """Ошибка"""

    @model_validator(mode="after")
    def check_oneof(cls, values):
        return cls._validate_field_groups(values)


@dataclass(eq=False, repr=False, config={"extra": "forbid"})
class PostBannerResponseError(betterproto.Message):
    """Ошибка запроса сохранения баннера"""

    validation: "ValidationError | None" = betterproto.message_field(
        1, optional=True, group="reason"
    )
    """Ошибка валидации"""

    saving: "BannerSavingError | None" = betterproto.message_field(
        2, optional=True, group="reason"
    )
    """Ошибка сохранения"""

    @model_validator(mode="after")
    def check_oneof(cls, values):
        return cls._validate_field_groups(values)


@dataclass(eq=False, repr=False, config={"extra": "forbid"})
class GetBannerRequest(betterproto.Message):
    """Запрос получения баннера"""

    id: str = betterproto.string_field(1)
    """
    Идентификатор баннера.
     # Тип: Guid
    """


@dataclass(eq=False, repr=False, config={"extra": "forbid"})
class GetBannerResponse(betterproto.Message):
    """Ответ на запрос получения баннера"""

    data: "Banner | None" = betterproto.message_field(1, optional=True, group="type")
    """Баннер"""

    error: "GetBannerResponseError | None" = betterproto.message_field(
        2, optional=True, group="type"
    )
    """Ошибка"""

    @model_validator(mode="after")
    def check_oneof(cls, values):
        return cls._validate_field_groups(values)


@dataclass(eq=False, repr=False, config={"extra": "forbid"})
class GetBannerResponseError(betterproto.Message):
    """Ошибка запроса получения баннера"""

    validation: "ValidationError | None" = betterproto.message_field(
        1, optional=True, group="reason"
    )
    """Ошибка валидации"""

    @model_validator(mode="after")
    def check_oneof(cls, values):
        return cls._validate_field_groups(values)


@dataclass(eq=False, repr=False, config={"extra": "forbid"})
class GetBannerLiteRequest(betterproto.Message):
    """Запрос получения упрощённого баннера"""

    id: str = betterproto.string_field(1)
    """
    Идентификатор баннера.
     # Тип: Guid
    """


@dataclass(eq=False, repr=False, config={"extra": "forbid"})
class GetBannerLiteResponse(betterproto.Message):
    """Ответ на запрос получения упрощённого баннера"""

    data: "BannerLite | None" = betterproto.message_field(
        1, optional=True, group="type"
    )
    """Упрощённый баннер"""

    error: "GetBannerLiteResponseError | None" = betterproto.message_field(
        2, optional=True, group="type"
    )
    """Ошибка"""

    @model_validator(mode="after")
    def check_oneof(cls, values):
        return cls._validate_field_groups(values)


@dataclass(eq=False, repr=False, config={"extra": "forbid"})
class GetBannerLiteResponseError(betterproto.Message):
    """Ошибка запроса получения упрощённого баннера"""

    validation: "ValidationError | None" = betterproto.message_field(
        1, optional=True, group="reason"
    )
    """Ошибка валидации"""

    @model_validator(mode="after")
    def check_oneof(cls, values):
        return cls._validate_field_groups(values)


@dataclass(eq=False, repr=False, config={"extra": "forbid"})
class GetBannerListRequest(betterproto.Message):
    """Запрос получения списка баннеров"""

    filter: "BannerFilter" = betterproto.message_field(1)
    """Фильтр"""

    paging: "BannerPaging | None" = betterproto.message_field(
        2, optional=True, group="pagination"
    )
    """Пагинация"""

    @model_validator(mode="after")
    def check_oneof(cls, values):
        return cls._validate_field_groups(values)


@dataclass(eq=False, repr=False, config={"extra": "forbid"})
class GetBannerListResponse(betterproto.Message):
    """Ответ на запрос получения списка баннеров"""

    data: "Banner | None" = betterproto.message_field(1, optional=True, group="type")
    """Баннер"""

    error: "GetBannerListResponseError | None" = betterproto.message_field(
        2, optional=True, group="type"
    )
    """Ошибка"""

    @model_validator(mode="after")
    def check_oneof(cls, values):
        return cls._validate_field_groups(values)


@dataclass(eq=False, repr=False, config={"extra": "forbid"})
class GetBannerListResponseError(betterproto.Message):
    """Ошибка запроса получения списка баннеров"""

    validation: "ValidationError | None" = betterproto.message_field(
        1, optional=True, group="reason"
    )
    """Ошибка валидации"""

    @model_validator(mode="after")
    def check_oneof(cls, values):
        return cls._validate_field_groups(values)


@dataclass(eq=False, repr=False, config={"extra": "forbid"})
class GetBannerLiteListRequest(betterproto.Message):
    """Запрос получения списка упрощённого баннеров"""

    filter: "BannerLiteFilter" = betterproto.message_field(1)
    """Упрощённый фильтр"""

    is_link_filter_disabled: bool = betterproto.bool_field(2)
    """Признак отключения фильтрации по типу платформы"""


@dataclass(eq=False, repr=False, config={"extra": "forbid"})
class GetBannerLiteListResponse(betterproto.Message):
    """Ответ на запрос получения списка упрощённых баннеров"""

    data: "BannerLite | None" = betterproto.message_field(
        1, optional=True, group="type"
    )
    """Упрощённый баннер"""

    error: "GetBannerLiteListResponseError | None" = betterproto.message_field(
        2, optional=True, group="type"
    )
    """Ошибка"""

    @model_validator(mode="after")
    def check_oneof(cls, values):
        return cls._validate_field_groups(values)


@dataclass(eq=False, repr=False, config={"extra": "forbid"})
class GetBannerLiteListResponseError(betterproto.Message):
    """Ошибка запроса получения списка баннеров"""

    validation: "ValidationError | None" = betterproto.message_field(
        1, optional=True, group="reason"
    )
    """Ошибка валидации"""

    @model_validator(mode="after")
    def check_oneof(cls, values):
        return cls._validate_field_groups(values)


@dataclass(eq=False, repr=False, config={"extra": "forbid"})
class GetBannerCountRequest(betterproto.Message):
    """Запрос получения количества баннеров"""

    filter: "BannerFilter" = betterproto.message_field(1)
    """Фильтр"""


@dataclass(eq=False, repr=False, config={"extra": "forbid"})
class GetBannerCountResponse(betterproto.Message):
    """Ответ на запрос получения количества баннеров"""

    data: "int | None" = betterproto.int32_field(1, optional=True, group="type")
    """Всего баннеров"""

    error: "GetBannerCountResponseError | None" = betterproto.message_field(
        2, optional=True, group="type"
    )
    """Ошибка"""

    @model_validator(mode="after")
    def check_oneof(cls, values):
        return cls._validate_field_groups(values)


@dataclass(eq=False, repr=False, config={"extra": "forbid"})
class GetBannerCountResponseError(betterproto.Message):
    """Ошибка запроса получения количества баннеров"""

    validation: "ValidationError | None" = betterproto.message_field(
        1, optional=True, group="reason"
    )
    """Ошибка валидации"""

    @model_validator(mode="after")
    def check_oneof(cls, values):
        return cls._validate_field_groups(values)


@dataclass(eq=False, repr=False, config={"extra": "forbid"})
class UploadImage(betterproto.Message):
    """Объект загружаемой картинки"""

    base64: str = betterproto.string_field(1)
    """
    Картинка в формате инлайн base64.
     Обязательное.
     Пример: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIA...".
     # Паттерн: /^data:\s*image\/(png|jpeg|jpg);\s*base64/
    """


@dataclass(eq=False, repr=False, config={"extra": "forbid"})
class PostBannerUploadImageRequest(betterproto.Message):
    """Запрос загрузки картинки баннера"""

    banner_id: str = betterproto.string_field(1)
    """
    Идентификатор баннера.
     Используется для складывания картинок баннера в папку баннера в бакете.
     Название картинки в папке создаётся из случайного Guid.
     # Тип: Guid
    """

    upload_image: "UploadImage" = betterproto.message_field(2)
    """Загружаемая картинка"""


@dataclass(eq=False, repr=False, config={"extra": "forbid"})
class PostBannerUploadImageResponse(betterproto.Message):
    """Ответ на запрос загрузки картинки баннера"""

    data: "str | None" = betterproto.string_field(1, optional=True, group="type")
    """
    Ссылка на баннер на imageproxy cdn сервер.
     Общедоступна в интернете
    """

    error: "PostBannerUploadImageResponseError | None" = betterproto.message_field(
        2, optional=True, group="type"
    )
    """Ошибка"""

    @model_validator(mode="after")
    def check_oneof(cls, values):
        return cls._validate_field_groups(values)


@dataclass(eq=False, repr=False, config={"extra": "forbid"})
class PostBannerUploadImageResponseError(betterproto.Message):
    """Ошибка запроса загрузки картинки баннера"""

    validation: "ValidationError | None" = betterproto.message_field(
        1, optional=True, group="reason"
    )
    """Ошибка валидации"""

    @model_validator(mode="after")
    def check_oneof(cls, values):
        return cls._validate_field_groups(values)


@dataclass(eq=False, repr=False, config={"extra": "forbid"})
class ValidationError(betterproto.Message):
    """
    Ошибки валидации.
     Эти проверки выполняются до обращения в базу данных
    """

    path: str = betterproto.string_field(1)
    """Путь к полю в формате наименования прото"""

    message: str = betterproto.string_field(2)
    """Валидационное сообщение"""


@dataclass(eq=False, repr=False, config={"extra": "forbid"})
class GetSystemStatusRequest(betterproto.Message):
    """Запрос проверки доступности сервиса"""

    pass


@dataclass(eq=False, repr=False, config={"extra": "forbid"})
class GetSystemStatusResponse(betterproto.Message):
    """Ответ на запрос проверки доступности сервиса"""

    pass


class BannerServiceStub(betterproto.ServiceStub):
    async def post_banner(
        self,
        post_banner_request: "PostBannerRequest",
        *,
        timeout: "float | None" = None,
        deadline: "Deadline | None" = None,
        metadata: "MetadataLike | None" = None
    ) -> "PostBannerResponse":
        return await self._unary_unary(
            "/keyapis.banner.v1.BannerService/PostBanner",
            post_banner_request,
            PostBannerResponse,
            timeout=timeout,
            deadline=deadline,
            metadata=metadata,
        )

    async def get_banner(
        self,
        get_banner_request: "GetBannerRequest",
        *,
        timeout: "float | None" = None,
        deadline: "Deadline | None" = None,
        metadata: "MetadataLike | None" = None
    ) -> "GetBannerResponse":
        return await self._unary_unary(
            "/keyapis.banner.v1.BannerService/GetBanner",
            get_banner_request,
            GetBannerResponse,
            timeout=timeout,
            deadline=deadline,
            metadata=metadata,
        )

    async def get_banner_lite(
        self,
        get_banner_lite_request: "GetBannerLiteRequest",
        *,
        timeout: "float | None" = None,
        deadline: "Deadline | None" = None,
        metadata: "MetadataLike | None" = None
    ) -> "GetBannerLiteResponse":
        return await self._unary_unary(
            "/keyapis.banner.v1.BannerService/GetBannerLite",
            get_banner_lite_request,
            GetBannerLiteResponse,
            timeout=timeout,
            deadline=deadline,
            metadata=metadata,
        )

    async def get_banner_list(
        self,
        get_banner_list_request: "GetBannerListRequest",
        *,
        timeout: "float | None" = None,
        deadline: "Deadline | None" = None,
        metadata: "MetadataLike | None" = None
    ) -> "AsyncIterator[GetBannerListResponse]":
        async for response in self._unary_stream(
            "/keyapis.banner.v1.BannerService/GetBannerList",
            get_banner_list_request,
            GetBannerListResponse,
            timeout=timeout,
            deadline=deadline,
            metadata=metadata,
        ):
            yield response

    async def get_banner_lite_list(
        self,
        get_banner_lite_list_request: "GetBannerLiteListRequest",
        *,
        timeout: "float | None" = None,
        deadline: "Deadline | None" = None,
        metadata: "MetadataLike | None" = None
    ) -> "AsyncIterator[GetBannerLiteListResponse]":
        async for response in self._unary_stream(
            "/keyapis.banner.v1.BannerService/GetBannerLiteList",
            get_banner_lite_list_request,
            GetBannerLiteListResponse,
            timeout=timeout,
            deadline=deadline,
            metadata=metadata,
        ):
            yield response

    async def get_banner_count(
        self,
        get_banner_count_request: "GetBannerCountRequest",
        *,
        timeout: "float | None" = None,
        deadline: "Deadline | None" = None,
        metadata: "MetadataLike | None" = None
    ) -> "GetBannerCountResponse":
        return await self._unary_unary(
            "/keyapis.banner.v1.BannerService/GetBannerCount",
            get_banner_count_request,
            GetBannerCountResponse,
            timeout=timeout,
            deadline=deadline,
            metadata=metadata,
        )

    async def post_banner_upload_image(
        self,
        post_banner_upload_image_request: "PostBannerUploadImageRequest",
        *,
        timeout: "float | None" = None,
        deadline: "Deadline | None" = None,
        metadata: "MetadataLike | None" = None
    ) -> "PostBannerUploadImageResponse":
        return await self._unary_unary(
            "/keyapis.banner.v1.BannerService/PostBannerUploadImage",
            post_banner_upload_image_request,
            PostBannerUploadImageResponse,
            timeout=timeout,
            deadline=deadline,
            metadata=metadata,
        )


class SystemServiceStub(betterproto.ServiceStub):
    async def get_system_status(
        self,
        get_system_status_request: "GetSystemStatusRequest",
        *,
        timeout: "float | None" = None,
        deadline: "Deadline | None" = None,
        metadata: "MetadataLike | None" = None
    ) -> "GetSystemStatusResponse":
        return await self._unary_unary(
            "/keyapis.banner.v1.SystemService/GetSystemStatus",
            get_system_status_request,
            GetSystemStatusResponse,
            timeout=timeout,
            deadline=deadline,
            metadata=metadata,
        )


class BannerServiceBase(ServiceBase):

    async def post_banner(
        self, post_banner_request: "PostBannerRequest"
    ) -> "PostBannerResponse":
        raise grpclib.GRPCError(grpclib.const.Status.UNIMPLEMENTED)

    async def get_banner(
        self, get_banner_request: "GetBannerRequest"
    ) -> "GetBannerResponse":
        raise grpclib.GRPCError(grpclib.const.Status.UNIMPLEMENTED)

    async def get_banner_lite(
        self, get_banner_lite_request: "GetBannerLiteRequest"
    ) -> "GetBannerLiteResponse":
        raise grpclib.GRPCError(grpclib.const.Status.UNIMPLEMENTED)

    async def get_banner_list(
        self, get_banner_list_request: "GetBannerListRequest"
    ) -> "AsyncIterator[GetBannerListResponse]":
        raise grpclib.GRPCError(grpclib.const.Status.UNIMPLEMENTED)
        yield GetBannerListResponse()

    async def get_banner_lite_list(
        self, get_banner_lite_list_request: "GetBannerLiteListRequest"
    ) -> "AsyncIterator[GetBannerLiteListResponse]":
        raise grpclib.GRPCError(grpclib.const.Status.UNIMPLEMENTED)
        yield GetBannerLiteListResponse()

    async def get_banner_count(
        self, get_banner_count_request: "GetBannerCountRequest"
    ) -> "GetBannerCountResponse":
        raise grpclib.GRPCError(grpclib.const.Status.UNIMPLEMENTED)

    async def post_banner_upload_image(
        self, post_banner_upload_image_request: "PostBannerUploadImageRequest"
    ) -> "PostBannerUploadImageResponse":
        raise grpclib.GRPCError(grpclib.const.Status.UNIMPLEMENTED)

    async def __rpc_post_banner(
        self, stream: "grpclib.server.Stream[PostBannerRequest, PostBannerResponse]"
    ) -> None:
        request = await stream.recv_message()
        response = await self.post_banner(request)
        await stream.send_message(response)

    async def __rpc_get_banner(
        self, stream: "grpclib.server.Stream[GetBannerRequest, GetBannerResponse]"
    ) -> None:
        request = await stream.recv_message()
        response = await self.get_banner(request)
        await stream.send_message(response)

    async def __rpc_get_banner_lite(
        self,
        stream: "grpclib.server.Stream[GetBannerLiteRequest, GetBannerLiteResponse]",
    ) -> None:
        request = await stream.recv_message()
        response = await self.get_banner_lite(request)
        await stream.send_message(response)

    async def __rpc_get_banner_list(
        self,
        stream: "grpclib.server.Stream[GetBannerListRequest, GetBannerListResponse]",
    ) -> None:
        request = await stream.recv_message()
        await self._call_rpc_handler_server_stream(
            self.get_banner_list,
            stream,
            request,
        )

    async def __rpc_get_banner_lite_list(
        self,
        stream: "grpclib.server.Stream[GetBannerLiteListRequest, GetBannerLiteListResponse]",
    ) -> None:
        request = await stream.recv_message()
        await self._call_rpc_handler_server_stream(
            self.get_banner_lite_list,
            stream,
            request,
        )

    async def __rpc_get_banner_count(
        self,
        stream: "grpclib.server.Stream[GetBannerCountRequest, GetBannerCountResponse]",
    ) -> None:
        request = await stream.recv_message()
        response = await self.get_banner_count(request)
        await stream.send_message(response)

    async def __rpc_post_banner_upload_image(
        self,
        stream: "grpclib.server.Stream[PostBannerUploadImageRequest, PostBannerUploadImageResponse]",
    ) -> None:
        request = await stream.recv_message()
        response = await self.post_banner_upload_image(request)
        await stream.send_message(response)

    def __mapping__(self) -> "dict[str, grpclib.const.Handler]":
        return {
            "/keyapis.banner.v1.BannerService/PostBanner": grpclib.const.Handler(
                self.__rpc_post_banner,
                grpclib.const.Cardinality.UNARY_UNARY,
                PostBannerRequest,
                PostBannerResponse,
            ),
            "/keyapis.banner.v1.BannerService/GetBanner": grpclib.const.Handler(
                self.__rpc_get_banner,
                grpclib.const.Cardinality.UNARY_UNARY,
                GetBannerRequest,
                GetBannerResponse,
            ),
            "/keyapis.banner.v1.BannerService/GetBannerLite": grpclib.const.Handler(
                self.__rpc_get_banner_lite,
                grpclib.const.Cardinality.UNARY_UNARY,
                GetBannerLiteRequest,
                GetBannerLiteResponse,
            ),
            "/keyapis.banner.v1.BannerService/GetBannerList": grpclib.const.Handler(
                self.__rpc_get_banner_list,
                grpclib.const.Cardinality.UNARY_STREAM,
                GetBannerListRequest,
                GetBannerListResponse,
            ),
            "/keyapis.banner.v1.BannerService/GetBannerLiteList": grpclib.const.Handler(
                self.__rpc_get_banner_lite_list,
                grpclib.const.Cardinality.UNARY_STREAM,
                GetBannerLiteListRequest,
                GetBannerLiteListResponse,
            ),
            "/keyapis.banner.v1.BannerService/GetBannerCount": grpclib.const.Handler(
                self.__rpc_get_banner_count,
                grpclib.const.Cardinality.UNARY_UNARY,
                GetBannerCountRequest,
                GetBannerCountResponse,
            ),
            "/keyapis.banner.v1.BannerService/PostBannerUploadImage": grpclib.const.Handler(
                self.__rpc_post_banner_upload_image,
                grpclib.const.Cardinality.UNARY_UNARY,
                PostBannerUploadImageRequest,
                PostBannerUploadImageResponse,
            ),
        }


class SystemServiceBase(ServiceBase):

    async def get_system_status(
        self, get_system_status_request: "GetSystemStatusRequest"
    ) -> "GetSystemStatusResponse":
        raise grpclib.GRPCError(grpclib.const.Status.UNIMPLEMENTED)

    async def __rpc_get_system_status(
        self,
        stream: "grpclib.server.Stream[GetSystemStatusRequest, GetSystemStatusResponse]",
    ) -> None:
        request = await stream.recv_message()
        response = await self.get_system_status(request)
        await stream.send_message(response)

    def __mapping__(self) -> "dict[str, grpclib.const.Handler]":
        return {
            "/keyapis.banner.v1.SystemService/GetSystemStatus": grpclib.const.Handler(
                self.__rpc_get_system_status,
                grpclib.const.Cardinality.UNARY_UNARY,
                GetSystemStatusRequest,
                GetSystemStatusResponse,
            ),
        }


rebuild_dataclass(Banner)  # type: ignore
rebuild_dataclass(BannerGradient)  # type: ignore
rebuild_dataclass(BannerGradientLinear)  # type: ignore
rebuild_dataclass(BannerImage)  # type: ignore
rebuild_dataclass(BannerLink)  # type: ignore
rebuild_dataclass(BannerSavingError)  # type: ignore
rebuild_dataclass(BannerLite)  # type: ignore
rebuild_dataclass(BannerLiteImageLite)  # type: ignore
rebuild_dataclass(BannerLiteLinkLite)  # type: ignore
rebuild_dataclass(BannerFilter)  # type: ignore
rebuild_dataclass(BannerLiteFilter)  # type: ignore
rebuild_dataclass(BannerPaging)  # type: ignore
rebuild_dataclass(PostBannerRequest)  # type: ignore
rebuild_dataclass(PostBannerResponse)  # type: ignore
rebuild_dataclass(PostBannerResponseError)  # type: ignore
rebuild_dataclass(GetBannerResponse)  # type: ignore
rebuild_dataclass(GetBannerResponseError)  # type: ignore
rebuild_dataclass(GetBannerLiteResponse)  # type: ignore
rebuild_dataclass(GetBannerLiteResponseError)  # type: ignore
rebuild_dataclass(GetBannerListRequest)  # type: ignore
rebuild_dataclass(GetBannerListResponse)  # type: ignore
rebuild_dataclass(GetBannerListResponseError)  # type: ignore
rebuild_dataclass(GetBannerLiteListRequest)  # type: ignore
rebuild_dataclass(GetBannerLiteListResponse)  # type: ignore
rebuild_dataclass(GetBannerLiteListResponseError)  # type: ignore
rebuild_dataclass(GetBannerCountRequest)  # type: ignore
rebuild_dataclass(GetBannerCountResponse)  # type: ignore
rebuild_dataclass(GetBannerCountResponseError)  # type: ignore
rebuild_dataclass(PostBannerUploadImageRequest)  # type: ignore
rebuild_dataclass(PostBannerUploadImageResponse)  # type: ignore
rebuild_dataclass(PostBannerUploadImageResponseError)  # type: ignore
