/*
  Сервис реализует функционал управления оповещениями о проблемах сбора показаний телеметрии (алертинга)
*/
syntax = "proto3";

import "google/api/annotations.proto";
import "google/api/field_behavior.proto";
import "google/protobuf/wrappers.proto";
import "google/protobuf/timestamp.proto";

package keyapis.telemetry_alerting.v1;

option java_package = "ru.keyapis.telemetry_alerting.v1";
option java_outer_classname = "KeyapisTelemetryAlertingV1Proto";
option java_multiple_files = false;
option java_string_check_utf8 = true;
option go_package = "/keyapis_telemetry_alerting_v1";
option cc_enable_arenas = true;
option csharp_namespace = "Keyapis.TelemetryAlerting.V1";
option objc_class_prefix = "KEYAPISTELEMETRYALERTINGYV1";
option php_namespace = "Keyapis\\TelemetryAlerting\\V1";
option ruby_package = "Keyapis::TelemetryAlerting::V1";
option optimize_for = LITE_RUNTIME;

// Сервис алертинга
service TriggerService {
  // Метод сохранения триггера.
  // Поддерживает создание и обновление.
  // Метод доступен для: service, application(telemetry:edit)
  rpc PostTrigger(PostTriggerRequest) returns (PostTriggerResponse) {
    option (google.api.http) = {
      post: "/telemetry_alerting/api/v1/trigger"
      body: "*"
    };
  }
  // Чтение одного триггера.
  // Метод доступен для: service, application(telemetry:read или telemetry:edit)
  rpc GetTrigger(GetTriggerRequest) returns (GetTriggerResponse) {
    option (google.api.http) = {
      get: "/telemetry_alerting/api/v1/trigger/{id}"
    };
  }
  // Метод получения списка триггеров.
  // Метод доступен для: service, application(telemetry:read или telemetry:edit)
  rpc GetTriggerList(GetTriggerListRequest) returns (stream GetTriggerListResponse) {
    option (google.api.http) = {
      get: "/telemetry_alerting/api/v1/trigger/list"
    };
  }
  // Метод получения количества триггеров.
  // Метод доступен для: service, application(telemetry:read или telemetry:edit)
  rpc GetTriggerCount(GetTriggerCountRequest) returns (GetTriggerCountResponse) {
    option (google.api.http) = {
      get: "/telemetry_alerting/api/v1/trigger/count"
    };
  }

  // Удаление триггера.
  // Метод удаляет только отключенный триггер (is_disabled=true).
  // Удаление неотключенного вызовет ошибку.
  // При удалении триггера удаляются и все его алерты.
  // Метод доступен для: service, application(telemetry:edit)
  rpc DeleteTrigger(DeleteTriggerRequest) returns (DeleteTriggerResponse) {
    option (google.api.http) = {
      delete: "/telemetry_alerting/api/v1/trigger/{id}"
    };
  }
  // Метод получения списка алертов.
  // Метод доступен для: service, application(telemetry:read или telemetry:edit)
  rpc GetTriggerAlertList(GetTriggerAlertListRequest) returns (stream GetTriggerAlertListResponse) {
    option (google.api.http) = {
      get: "/telemetry_alerting/api/v1/trigger/alert/list"
    };
  }
  // Метод получения количества алертов.
  // Метод доступен для: service, application(telemetry:read или telemetry:edit)
  rpc GetTriggerAlertCount(GetTriggerAlertCountRequest) returns (GetTriggerAlertCountResponse) {
    option (google.api.http) = {
      get: "/telemetry_alerting/api/v1/trigger/alert/count"
    };
  }
  // Удаление алерта.
  // Метод удаляет только погашенный алерт (is_disabled=true).
  // Удаление непогашенного вызовет ошибку.
  // Метод доступен для: service, application(telemetry:edit)
  rpc DeleteTriggerAlert(DeleteTriggerAlertRequest) returns (DeleteTriggerAlertResponse) {
    option (google.api.http) = {
      delete: "/telemetry_alerting/api/v1/trigger/alert/{id}"
    };
  }
  // Принудительное выключение алерта.
  // Дата closed_at проставляется текущим временем.
  // Флаг is_disabled проставляется true.
  // Флаг is_manually_closed проставляется true.
  // Можно принудительно выключать только алерты созданные по триггерам с атрибутом manually_unclosable=false.
  // Метод доступен для: service, application(telemetry:edit)
  rpc PostTriggerAlertDisable(PostTriggerAlertDisableRequest) returns (PostTriggerAlertDisableResponse) {
    option (google.api.http) = {
      post: "/telemetry_alerting/api/v1/trigger/alert/{id}/disable"
    };
  }
  // Список устройств, вызвавших появление алерта.
  // Метод доступен для: service, application(telemetry:read или telemetry:edit)
  rpc GetTriggerAlertDeviceList(GetTriggerAlertDeviceListRequest) returns (stream GetTriggerAlertDeviceListResponse) {
    option (google.api.http) = {
      get: "/telemetry_alerting/api/v1/trigger/alert/{id}/device/list"
    };
  }
}

// Запрос списка устройств, вызвавших появление алерта
message GetTriggerAlertDeviceListRequest {
  // Идентификатор алерта
  int32 id = 1 [(google.api.field_behavior) = REQUIRED];
  // Параметры фильтрации алерта
  TriggerAlertFilter filter = 2;
  // Вариант разбиения на страницы
  oneof pagination {
    // Параметры пагинации
    TriggerAlertPaging paging = 3;
  }
}

// Параметры пагинации алертов
message TriggerAlertPaging {
  // Справочник типов значений сортировки
  enum OrderByType {
    // Значение не указано
    ORDER_BY_TYPE_UNKNOWN = 0;
    // По дате возникновения
    RAISED_AT = 1;
    // По идентификатору триггера
    TRIGGER_ID = 2;
    // По заголовку триггера
    TITLE = 3;
    // По флагу активности триггера
    DISABLED = 4;
    // По триггеру
    SEVERITY = 5;
  }
  // Тип значения сортировки.
  // По умолчанию: ORDER_BY_TYPE_RAISED_AT
  OrderByType order_by_type = 1;
  // Справочник типов направлений сортировки
  enum DirectionType {
    // Значение не указано
    DIRECTION_TYPE_UNKNOWN = 0;
    // От большего к меньшему
    DESC = 1;
    // От меньшего к большему
    ASC = 2;
  }
  // Тип направления сортировки.
  // По умолчанию: DESC
  DirectionType direction_type = 2;
  // Сколько элементов нужно получить за раз.
  // Минимальное значение: 1.
  // Максимальное значение: 100.
  // По умолчанию: 20.
  // Если значение 0 (не передано), то выставляем значение по умолчанию
  int32 limit = 3;
  // Начальный сдвиг.
  // По умолчанию: 0
  int32 offset = 4;
}

// Факты сработки алерта на устройствах
message AlertDevice {
  // Идентификатор алерта
  int32 alert_id = 1 [(google.api.field_behavior) = REQUIRED];
  // Идентификатор устройства
  int32 device_id = 2 [(google.api.field_behavior) = REQUIRED];
}

// Ответ на запрос списка устройств, вызвавших появление алерта
message GetTriggerAlertDeviceListResponse {
  // Тип результата
  oneof type {
    // Факт сработки триггера
    AlertDevice data = 1;
  }
}

// Запрос на чтение триггера
message GetTriggerRequest {
  // Идентификатор триггера
  int32 id = 1 [(google.api.field_behavior) = REQUIRED];
}

// Ответ на чтение триггера
message GetTriggerResponse {
  // Тип результата
  oneof type {
    // Триггер
    Trigger data = 1;
  }
}

// Запрос получения списка алертов
message GetTriggerAlertListRequest {
  // Параметры фильтрации
  TriggerAlertFilter filter = 1;
  // Вариант разбиения на страницы
  oneof pagination {
    // Параметры пагинации
    TriggerAlertPaging paging = 2;
  }
}

// Запрос на погашение алерта
message PostTriggerAlertDisableRequest {
  // Идентификатор алерта
  int32 id = 1 [(google.api.field_behavior) = REQUIRED];
  // Причина принудительного закрытия, заполняется в момент принудительного закрытия
  google.protobuf.StringValue closing_reason = 2;
}

// Ответ на запрос погашение алерта
message PostTriggerAlertDisableResponse {}

// Запрос получения списка алертов
message GetTriggerAlertCountRequest {
  // Параметры фильтрации
  TriggerAlertFilter filter = 1;
}

// Запрос получения списка триггеров
message GetTriggerListRequest {
  // Параметры фильтрации
  TriggerFilter filter = 1;
  // Вариант разбиения на страницы
  oneof pagination {
    // Параметры пагинации
    TriggerPaging paging = 2;
  }
}

// Параметры пагинации триггеров
message TriggerPaging {
  // Справочник типов значений сортировки
  enum OrderByType {
    // Значение не указано
    ORDER_BY_TYPE_UNKNOWN = 0;
    // По идентификатору
    ID = 1;
    // По заголовку
    TITLE = 2;
    // По флагу активности
    DISABLED = 3;
    // По Severity
    SEVERITY = 4;
  }
  // Тип значения сортировки.
  // По умолчанию: SEVERITY
  OrderByType order_by_type = 1;
  // Справочник типов направлений сортировки
  enum DirectionType {
    // Значение не указано
    DIRECTION_TYPE_UNKNOWN = 0;
    // От большего к меньшему
    DESC = 1;
    // От меньшего к большему
    ASC = 2;
  }
  // Тип направления сортировки.
  // По умолчанию: ASC
  DirectionType direction_type = 2;
  // Сколько элементов нужно получить за раз.
  // Минимальное значение: 1.
  // Максимальное значение: 100.
  // По умолчанию: 20.
  // Если значение 0 (не передано), то выставляем значение по умолчанию
  int32 limit = 3;
  // Начальный сдвиг.
  // По умолчанию: 0
  int32 offset = 4;
}

// Параметры фильтрации триггеров.
// При передаче массива в параметр фильтра элементы массива работают в выборке через ИЛИ.
// При передаче нескольких разных параметров фильтра они работают в выборке через И
message TriggerFilter {
  // По уровням критичности
  repeated Trigger.SeverityType severity_types = 1;
  // По тэгам
  repeated string tags = 2;
  // По типам метрик триггеров
  repeated Trigger.MetricType metric_types = 3;
  // По моделям устройств
  repeated string device_models = 4;
  // По типам устройств
  repeated Trigger.DeviceType device_types = 5;
  // По типам группировки метрик
  repeated Trigger.MetricGroupingType metric_grouping_types = 6;
  // По признаку активности триггера
  google.protobuf.BoolValue is_disabled = 7;
}

// Параметры фильтрации алертов.
// При передаче массива в параметр фильтра элементы массива работают в выборке через ИЛИ.
// При передаче нескольких разных параметров фильтра они работают в выборке через И
message TriggerAlertFilter {
  // По важности триггера
  repeated Trigger.SeverityType trigger_severity_types = 1;
  // По ФИАСам
  repeated string fias_ids = 2;
  // По тэгам
  repeated string tags = 3;
  // По типам метрик триггера
  repeated Trigger.MetricType metric_types = 4;
  // По моделям устройств
  repeated string device_models = 5;
  // По типам устройств
  repeated Trigger.DeviceType device_types = 6;
  // По идентификаторам родительских устройств
  repeated int32 device_parent_ids = 7;
  // По идентификаторам устройств
  repeated int32 device_ids = 8;
  // По признаку активности
  google.protobuf.BoolValue is_disabled = 9;
  // От даты возникновения включительно (>=)
  google.protobuf.Timestamp after_raised_at = 10;
  // До даты возникновения (<)
  google.protobuf.Timestamp before_raised_at = 11;
  // По типам группировки метрик
  repeated Trigger.MetricGroupingType metric_grouping_types = 12;
  // По идентификаторам триггеров
  repeated int32 trigger_ids = 13;
}

// Триггер
message Trigger {
  // Идентификатор
  int32 id = 1;
  // Дата последнего изменения.
  // Заполняется и обновляется сервером.
  // Заполняется при создании и изменении.
  // Является версией объекта
  google.protobuf.Timestamp changed_at = 2 [(google.api.field_behavior) = OUTPUT_ONLY];
  // Название триггера
  string title = 3 [(google.api.field_behavior) = REQUIRED];
  // Справочник типов критерия триггера.
  // Задает параметры критерия, правила поиска проблемы и генерации алерта
  enum CriteriaType {
    // Значение не указано
    CRITERIA_TYPE_UNKNOWN = 0;
    // Количество метрик меньше порога
    METRICS_COUNT = 1;
    // Доля работающих устройств в группе меньше порога
    DEVICE_PERCENT = 2;
    // Превышение порога дисперсии значений показаний
    METRICS_VALUE_DEVIATION = 3;
  }
  // Тип критерия триггера
  CriteriaType criteria_type = 4 [(google.api.field_behavior) = REQUIRED];
  // Пороговое значение триггера
  float threshold = 5  [(google.api.field_behavior) = REQUIRED];
  // Границы временного окна, в текущем или предыдущем месяце.
  // Если end_day текущего месяца не наступил, то берем прошлый месяц
  message FixedDaysOfMonth {
    // Начало окна времени.
    // Номер дня месяца, момент времени 00:00:00.000 UTC
    int32 start_day = 1;
    // Конец окна времени.
    // Номер дня месяца, момент времени 00:00:00.000 UTC
    int32 end_day = 2;
  }
  // Временное окно выборки метрик
  oneof range {
    // Скользящее окно относительно текущего момента.
    // Начало окна это 00:00:00.000 UTC дня на sliding_days раньше текущего UTC дня.
    // Конец окна - текущий момент
    int32 sliding_days = 6;
    // Границы временного окна, в текущем или предыдущем месяце
    FixedDaysOfMonth fixed_days_range = 7;
  }
  // Справочник типов периодов контроля триггера
  enum PeriodType {
    // Значение не указано
    PERIOD_TYPE_UNKNOWN = 0;
    // День
    DAY = 1;
    // Месяц
    MONTH = 2;
  }
  // Тип периода контроля
  PeriodType period_type = 8 [(google.api.field_behavior) = REQUIRED];
  // Справочник типов уровней критичности
  enum SeverityType {
    // Значение не указано
    SEVERITY_TYPE_UNKNOWN = 0;
    // Проблема высшего приоритета.
    // Максимальное оповещение
    CRITICAL = 1;
    // Проблема среднего приоритета.
    // Оповещение по внутренним каналам
    WARNING = 2;
    // Проблема не влияет на бизнес-пользователя.
    // Отражается во внутренних интерфейсах
    INFO = 3;
  }
  // Уровень критичности проблемы, которая описана критерием.
  // Задает приоритет оповещения и реагирования
  SeverityType severity_type = 9 [(google.api.field_behavior) = REQUIRED];
  // Флаг активности триггера.
  // При погашении триггера гасятся и все его алерты
  bool is_disabled = 10 [(google.api.field_behavior) = REQUIRED];
  // Краткая инструкция по решению или эскалации проблемы
  google.protobuf.StringValue instruction = 11;
  // Справочник типов энергоресурсов, собираемых ТУ
  enum MetricType {
    // Значение не указано
    METRIC_TYPE_UNKNOWN = 0;
    // Горячая вода
    HOT_WATER = 1;
    // Холодная вода
    COLD_WATER = 2;
    // Теплоэнергия
    HEAT = 3;
    // Газ
    GAS = 4;
    // Электроэнергия
    ELECTRICITY = 5;
  }
  // Фильтрация метрик по типам метрик.
  // При нескольких элементах фильтрация срабатывает по значениям через ИЛИ
  repeated MetricType metric_types = 12;
  // Фильтрация метрик по значению моделей устройств.
  // При нескольких элементах фильтрация срабатывает по значениям через ИЛИ
  repeated string device_models = 13;
  // Справочник типов ПУ
  enum DeviceType {
    // Значение не указано
    DEVICE_TYPE_UNKNOWN = 0;
    // Коммуникационный модуль
    HUB = 1;
    // Счетчик импульсов - регистратор
    PULSE_COUNTER_RECORDER = 2;
    // Счетчик импульсов - регистратор LoRaWAN
    PULSE_COUNTER_RECORDER_LR = 3;
    // Прибор учета расхода коммунальных услуг
    METERING_DEVICE = 4;
    // Конвертер интерфейсов
    INTERFACE_CONVERTER = 5;
    // M-BUS концентратор
    M_BUS_HUB = 6;
    // Модуль связи LoRaWAN
    COMMUNICATION_MODULE_LR = 7;
    // Базовая станция LoRaWAN
    BASE_LR = 8;
  }
  // Фильтрация метрик по значению типов устройств.
  // При нескольких элементах фильтрация срабатывает по значениям через ИЛИ
  repeated DeviceType device_types = 14;
  // Типы группировок метрик при вычислении критерия
  enum MetricGroupingType {
    // Значение не указано
    METRIC_GROUPING_TYPE_UNKNOWN = 0;
    // Признак группировки метрик по идентификаторам родительского устройства(идентификатор хаба, проксирующего прибор учета)
    PARENT_ID = 1;
    // Признак группировки метрик по идентификатору устройства(устройство, с которого получена метрика)
    DEVICE_ID = 2;
  }
  // Тип группировки метрик при вычислении критерия
  MetricGroupingType metric_grouping_type = 15;
  // Количество отрицательных проверок критерия, после которого сервис отключает
  int32 success_threshold = 16;
  // Произвольные теги для фильтрации и упорядочивания
  repeated string tags = 17;
  // Флаг невозможности погашения алертов этого триггера
  bool is_manually_unclosable = 18;
  // Признак контроля триггером временного окна выборки метрик на основе поля индикатора metric_expected_freq.
  // При значении true: поля range.sliding_days, range.fixed_days_range игнорируются при работе триггера.
  // При значении true: временное окно выборки метрик при работе триггера работает как sliding_days=indicator.metric_expected_freq.
  // При значении true: Для случаев indicator.metric_expected_freq=null индикатор игнорируется при работе триггера, алерт по нему не создается.
  // При значении true: Для случаев indicator.metric_expected_freq<=0 индикатор игнорируется при работе триггера, алерт по нему не создается
  bool is_range_metric_expected_freq = 19;

  // Определение проблемы, сгенерированной по триггеру
  message Alert {
    // Идентификатор
    int32 id = 1 [(google.api.field_behavior) = OUTPUT_ONLY];
    // Дата последнего изменения.
    // Заполняется и обновляется сервером.
    // Заполняется при создании и изменении.
    // Является версией объекта
    google.protobuf.Timestamp changed_at = 2 [(google.api.field_behavior) = OUTPUT_ONLY];
    // Породивший триггер
    int32 trigger_id = 3 [(google.api.field_behavior) = REQUIRED];
    // ФИАС
    string fias_id = 4 [(google.api.field_behavior) = REQUIRED];
    // Время возникновения алерта
    google.protobuf.Timestamp raised_at = 5 [(google.api.field_behavior) = REQUIRED];
    // Признак погашенного алерта.
    // Проставляется сервисом при no_alarm_checks_count >= success_threshold
    bool is_disabled = 6 [(google.api.field_behavior) = REQUIRED];
    // Количество проверок триггера для атрибутов данного алерта, при которых не выполнился критерий триггера.
    // Увеличивается у непогашенного алерта, если при очередной проверке нет срабатывания триггера с атрибутами данного алерта.
    // При увеличении проставляется changed_at
    int32 no_alarm_checks_count = 7 [(google.api.field_behavior) = REQUIRED];
    // Типы метрик, по которым были отфильтрованы метрики
    repeated Trigger.MetricType trigger_metric_types = 8;
    // Модели устройств, по которым были отфильтрованы метрики
    repeated string device_models = 9;
    // Типы устройств, по которым были отфильтрованы метрики
    repeated Trigger.DeviceType trigger_device_types = 10;
    // Идентификаторы родительских устройств, по которому были сгруппированы метрики
    google.protobuf.Int32Value device_parent_id = 11;
    // Время погашения алерта.
    // Пустой или отсутствует у непогашенного активного алерта
    google.protobuf.Timestamp closed_at = 12;
    // Признак принудительного погашения алерта
    bool is_manually_closed = 13;
    // Причина принудительного закрытия, заполняется в момент принудительного закрытия
    google.protobuf.StringValue closing_reason = 14;
    // Группировка метрик при вычислении критерия
    Trigger.MetricGroupingType trigger_metric_grouping_type = 15;
  }
}

// Ответ на запрос получения списка записей
message GetTriggerListResponse {
  // Тип результата
  oneof type {
    // Триггер
    Trigger data = 1;
  }
}
// Ответ на запрос получения списка записей
message GetTriggerAlertListResponse {
  // Тип результата
  oneof type {
    // Алерт
    Trigger.Alert data = 1;
  }
}

// Запрос получения количества записей
message GetTriggerCountRequest {
  // Параметры фильтрации
  TriggerFilter filter = 1;
}
// Ответ на запрос получения количества записей
message GetTriggerCountResponse {
  // Тип результата
  oneof type {
    // Всего записей
    int32 data = 1;
  }
}

// Ответ на запрос получения количества записей
message GetTriggerAlertCountResponse {
  // Тип результата
  oneof type {
    // Всего записей
    int32 data = 1;
  }
}

// Запрос на создание триггера
message PostTriggerRequest {
  // Триггер, который хотим создать или обновить
  Trigger data = 1 [(google.api.field_behavior) = REQUIRED];
}
// Ответ на запрос сохранения триггера
message PostTriggerResponse {
  // Тип результата
  oneof type {
    // Триггер, созданный или обновленный
    Trigger data = 1;
  }
}

// Запрос на удаление триггера
message DeleteTriggerRequest {
  // Идентификатор триггера
  int32 id = 1 [(google.api.field_behavior) = REQUIRED];
}
// Ответ на запрос удаление триггера
message DeleteTriggerResponse {}

// Запрос на удаление алерта
message DeleteTriggerAlertRequest {
  // Идентификатор алерта
  int32 id = 1 [(google.api.field_behavior) = REQUIRED];
}
// Ответ на запрос удаление алерта
message DeleteTriggerAlertResponse {}
