// MIT License

// Copyright (c) 2023 Anton Tsitavets

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
 
// https://github.com/Bayselonarrend/OpenIntegrations

#Область ПрограммныйИнтерфейс

#Область НастройкиИИнформация

// ВАЖНО: Установка Webhook обязательна по правилам Viber. Для этого надо иметь свободный URL,
// который будет возвращать 200 и подлинный SSL сертификат. Если есть сертификат и база опубликована
// на сервере - можно использовать http-сервис. Туда же будет приходить и информация о новых сообщениях
// Viber периодически стучит по адресу Webhook, так что если он будет неактивен, то все перестанет работать
// 
// Параметры:
//  Токен - Строка - Токен Viber
//  URL - Строка - URL для установки Webhook
// 
// Возвращаемое значение:
// Произвольный - Ответ сервера Viber 
Функция УстановитьWebhook(Знач Токен, Знач URL) Экспорт
    
    СтруктураПараметров = Новый Структура;
    СтруктураПараметров.Вставить("url"       , URL);
    СтруктураПараметров.Вставить("auth_token", Токен);
    
    Возврат OPI_Инструменты.Post("https://chatapi.viber.com/pa/set_webhook"
        , СтруктураПараметров);
    
КонецФункции

// Тут можно получить ID пользователей канала. ID для бота необходимо получать из прилетов на Webhook
// ID пользователя из информации о канале не подойдет для отправки сообщений через бота - они разные
// 
// Параметры:
//  Токен - Строка - Токен
// 
// Возвращаемое значение:
//  ДвоичныеДанные, Неопределено, Произвольный -  Получить информацию о канале
Функция ПолучитьИнформациюОКанале(Знач Токен) Экспорт
    
    Возврат OPI_Инструменты.Get("https://chatapi.viber.com/pa/get_account_info"
        ,
        , ТокенВЗаголовки(Токен));
    
КонецФункции

// Получить данные пользователя.
// 
// Параметры:
//  Токен - Строка - Токен
//  IDПользователя - Строка, Число - ID пользователя Viber
// 
// Возвращаемое значение:
//  Произвольный, HTTPОтвет -  Ответ сервера Viber
Функция ПолучитьДанныеПользователя(Знач Токен, Знач IDПользователя) Экспорт
    
    СтруктураПараметров = Новый Структура;
    СтруктураПараметров.Вставить("id", IDПользователя);
    
    Ответ = OPI_Инструменты.Post("https://chatapi.viber.com/pa/get_user_details"
        , СтруктураПараметров
        , ТокенВЗаголовки(Токен));

    Попытка
        Возврат OPI_Инструменты.JsonВСтруктуру(Ответ.ПолучитьТелоКакДвоичныеДанные());
    Исключение
        Возврат Ответ;
    КонецПопытки;
        
КонецФункции

// Получить онлайн пользователей.
// 
// Параметры:
//  Токен - Строка - Токен Viber
//  IDПользователей - Строка,Число,Массив из Строка,Число - ID пользователей(-я) Viber
// 
// Возвращаемое значение:
//  Произвольный, HTTPОтвет - Ответ сервера Viber
Функция ПолучитьОнлайнПользователей(Знач Токен, Знач IDПользователей) Экспорт
    
    Если Не ТипЗнч(IDПользователей) = Тип("Массив") Тогда
        
        ОдиночныйID     = IDПользователей;
        IDПользователей = Новый Массив;
        IDПользователей.Добавить(ОдиночныйID);
        
    КонецЕсли;
    
    СтруктураПараметров = Новый Структура;
    СтруктураПараметров.Вставить("ids", IDПользователей);
    
    Ответ = OPI_Инструменты.Post("https://chatapi.viber.com/pa/get_online"
        , СтруктураПараметров
        , ТокенВЗаголовки(Токен));
    
    Попытка
        Возврат OPI_Инструменты.JsonВСтруктуру(Ответ.ПолучитьТелоКакДвоичныеДанные());
    Исключение
        Возврат Ответ;
    КонецПопытки;

КонецФункции

#КонецОбласти

#Область ОтправкаСообщений

// Отправить текстовое сообщение.
// 
// Параметры:
//  Токен - Строка - Токен
//  Текст - Строка - Текст сообщения
//  IDПользователя - Строка,Число - ID пользователя Viber
//  ОтправкаВКанал - Булево - Отправка в канал или в чат бота
//  Клавиатура - Структура из Строка -  См. СформироватьКлавиатуруИзМассиваКнопок
// 
// Возвращаемое значение:
//  Произвольный, HTTPОтвет -  Ответ сервера Viber
Функция ОтправитьТекстовоеСообщение(Знач Токен
    , Знач Текст
    , Знач IDПользователя
    , Знач ОтправкаВКанал
    , Знач Клавиатура = "") Экспорт
    
    Возврат ОтправитьСообщение(Токен, "text", IDПользователя, ОтправкаВКанал, , Текст, Клавиатура); 
    
КонецФункции

// Отправить картинку.
// 
// Параметры:
//  Токен - Строка - Токен
//  URL - Строка - URL картинки
//  IDПользователя - Строка,Число - ID пользователя Viber
//  ОтправкаВКанал - булево - Отправка в канал или в чат бота
//  Описание - Строка -  Аннотация к картинке
// 
// Возвращаемое значение:
//  Произвольный, HTTPОтвет -  Ответ сервера Viber
Функция ОтправитьКартинку(Знач Токен, Знач URL, Знач IDПользователя, Знач ОтправкаВКанал, Знач Описание = "") Экспорт
    
    Возврат ОтправитьСообщение(Токен, "picture", IDПользователя, ОтправкаВКанал, URL, Описание);
    
КонецФункции

// Отправить файл.
// 
// Параметры:
//  Токен - Строка - Токен
//  URL - Строка - URL
//  IDПользователя - Строка,Число - ID пользователя Viber
//  ОтправкаВКанал - Булево - Отправка в канал или в чат бота
//  Расширение - Строка - Расширение файла
//  Размер - Число -  Размер файла. Если не заполнен - определяется автоматически, но при этом происходит скачивание
// 
// Возвращаемое значение:
//  Произвольный, HTTPОтвет -  Ответ сервера Viber
Функция ОтправитьФайл(Знач Токен
    , Знач URL
    , Знач IDПользователя
    , Знач ОтправкаВКанал
    , Знач Расширение
    , Знач Размер = "") Экспорт
    
    Если Не ЗначениеЗаполнено(Размер) Тогда
        
        Ответ = OPI_Инструменты.Get(URL);
        ИВФ   = ПолучитьИмяВременногоФайла(Расширение);
        Ответ.Записать(ИВФ);

        ВремФайл    = Новый Файл(ИВФ);
        Размер      = ВремФайл.Размер();
        УдалитьФайлы(ИВФ);
        
    КонецЕсли;
    
    Расширение = СтрЗаменить(Расширение, ".", "");
    
    СтруктураЗначения = Новый Структура;
    СтруктураЗначения.Вставить("URL"        , URL);
    СтруктураЗначения.Вставить("Размер"     , Размер);
    СтруктураЗначения.Вставить("Расширение" , Расширение);
    
    Возврат ОтправитьСообщение(Токен, "file", IDПользователя, ОтправкаВКанал, СтруктураЗначения);
    
КонецФункции

// Отправить контакт.
// 
// Параметры:
//  Токен - Строка - Токен
//  ИмяКонтакта - Строка - Имя контакта
//  НомерТелефона - Строка - Номер телефона
//  IDПользователя - Строка - ID пользователя Viber
//  ОтправкаВКанал - Булево - Отправка в канал или в чат бота
// 
// Возвращаемое значение:
//  Произвольный, HTTPОтвет -  Ответ сервера Viber
Функция ОтправитьКонтакт(Знач Токен
    , Знач ИмяКонтакта
    , Знач НомерТелефона
    , Знач IDПользователя
    , Знач ОтправкаВКанал) Экспорт
    
    СтруктураКонтакта = Новый Структура;
    СтруктураКонтакта.Вставить("name", ИмяКонтакта);
    СтруктураКонтакта.Вставить("phone_number", Строка(НомерТелефона));
    
    Возврат ОтправитьСообщение(Токен, "contact", IDПользователя, ОтправкаВКанал, СтруктураКонтакта); 
    
КонецФункции

// Отправить локацию.
// 
// Параметры:
//  Токен - Строка - Токен
//  Широта - Строка,Число - Географическая широта
//  Долгота - Строка,Число - Географическая долгота
//  IDПользователя - Строка,Число - ID пользователя Viber
//  ОтправкаВКанал - Булево - Отправка в канал или чат-боту
// 
// Возвращаемое значение:
//  Произвольный, HTTPОтвет -  Отправить локацию
Функция ОтправитьЛокацию(Знач Токен, Знач Широта, Знач Долгота, Знач IDПользователя, Знач ОтправкаВКанал) Экспорт
    
    СтруктураЛокации = Новый Структура;
    СтруктураЛокации.Вставить("lat", OPI_Инструменты.ЧислоВСтроку(Широта));
    СтруктураЛокации.Вставить("lon", OPI_Инструменты.ЧислоВСтроку(Долгота));
    
    Возврат ОтправитьСообщение(Токен, "location", IDПользователя, ОтправкаВКанал, СтруктураЛокации);
    
КонецФункции

// Отправить ссылку.
// 
// Параметры:
//  Токен - Строка - Токен
//  URL - Строка - Отправляемая ссылка
//  IDПользователя - Строка,Число - IDПользователя
//  ОтправкаВКанал - Булево - Отправка в канал или в чат боту
// 
// Возвращаемое значение:
//  Произвольный, HTTPОтвет -  Ответ сервера Viber
Функция ОтправитьСсылку(Знач Токен, Знач URL, Знач IDПользователя, Знач ОтправкаВКанал) Экспорт
    
    Возврат ОтправитьСообщение(Токен, "url", IDПользователя, ОтправкаВКанал, URL);
    
КонецФункции

// Сформировать клавиатуру из массива кнопок.
// 
// Параметры:
//  МассивКнопок - Массив из Строка - Массив кнопок
//  ЦветКнопок - Строка -  HEX цвет кнопок с # в начале
// 
// Возвращаемое значение:
//  Структура -  Сформировать клавиатуру из массива кнопок:
// * Buttons - Массив из Структура - Массив сформированных кнопок 
// * Type - Строка - Тип клавиатуры 
Функция СформироватьКлавиатуруИзМассиваКнопок(Знач МассивКнопок, Знач ЦветКнопок = "") Экспорт
    
    МассивСтруктурКнопок = Новый Массив;
    СтруктураКлавиатуры  = Новый Структура;
    ЦветКнопок           = ?(ЗначениеЗаполнено(ЦветКнопок), ЦветКнопок, "#2db9b9");
    
    Для Каждого ТекстКнопки Из МассивКнопок Цикл
        
        СтруктураКнопки = Новый Структура;
        СтруктураКнопки.Вставить("ActionType", "reply");
        СтруктураКнопки.Вставить("ActionBody", ТекстКнопки);
        СтруктураКнопки.Вставить("Text"      , ТекстКнопки);
        СтруктураКнопки.Вставить("BgColor"   , ЦветКнопок);
        СтруктураКнопки.Вставить("Coloumns"  , 3);
    
        МассивСтруктурКнопок.Добавить(СтруктураКнопки);
        
    КонецЦикла;
    
    СтруктураКлавиатуры.Вставить("Buttons", МассивСтруктурКнопок);
    СтруктураКлавиатуры.Вставить("Type"   , "keyboard");
    
    Возврат СтруктураКлавиатуры;
    
КонецФункции

#КонецОбласти

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

// Отправить сообщение.
// 
// Параметры:
//  Токен - Строка - Токен
//  Тип - Строка -  Тип отправляемого сообщения
//  IDПользователя - Строка,Число - ID пользователя Viber
//  ЭтоКанал - Булево - Отправка в канал или чат с ботом
//  Значение - Строка, Структура -  Значение:
// * URL - Строка - При отправке  URL
// * Размер - Число, Строка - Размер файла в случае отправке
// * Расширение - Строка - Расширение файла в случае отправки
//  Текст - Строка -  Текст сообщения
//  Клавиатура - Структура из Строка -  Клавиатура, если нужна, см. СформироватьКлавиатуруИзМассиваКнопок 
// 
// Возвращаемое значение:
//  Произвольный, HTTPОтвет -  Отправить сообщение
Функция ОтправитьСообщение(Знач Токен
    , Знач Тип
    , Знач IDПользователя
    , Знач ЭтоКанал
    , Знач Значение = ""
    , Знач Текст = ""
    , Знач Клавиатура = "")
    
    СтруктураПараметров = ВернутьСтандартныеПараметры();
    СтруктураПараметров.Вставить("type", Тип);  
    
    Если (Тип = "text" Или Тип = "picture") И ЗначениеЗаполнено(Текст) Тогда
        СтруктураПараметров.Вставить("text", Текст);
    КонецЕсли;
    
    Если ТипЗнч(Клавиатура) = Тип("Структура") Тогда
        СтруктураПараметров.Вставить("keyboard", Клавиатура);
    КонецЕсли;
    
    Если ЗначениеЗаполнено(Значение) Тогда
        
        Если Тип = "file" Тогда
            СтруктураПараметров.Вставить("media"    , Значение["URL"]);
            СтруктураПараметров.Вставить("size"     , Значение["Размер"]);
            СтруктураПараметров.Вставить("file_name", "Файл." + Значение["Расширение"]);
        ИначеЕсли Тип = "contact" Тогда
            СтруктураПараметров.Вставить("contact"  , Значение);
        ИначеЕсли Тип = "location" Тогда
            СтруктураПараметров.Вставить("location" , Значение);
        Иначе
            СтруктураПараметров.Вставить("media"    , Значение);
        КонецЕсли;
        
    КонецЕсли;
    
    Если ЭтоКанал Тогда
        СтруктураПараметров.Вставить("from", IDПользователя);
        URL = "https://chatapi.viber.com/pa/post";
    Иначе   
        СтруктураПараметров.Вставить("receiver", IDПользователя);
        URL = "https://chatapi.viber.com/pa/send_message";
    КонецЕсли;
    
    Ответ = OPI_Инструменты.Post(URL
        , СтруктураПараметров
        , ТокенВЗаголовки(Токен));
    
    Попытка
        Возврат OPI_Инструменты.JsonВСтруктуру(Ответ.ПолучитьТелоКакДвоичныеДанные());
    Исключение
        Возврат Ответ;
    КонецПопытки;
    
КонецФункции

Функция ВернутьСтандартныеПараметры() 
    
    СтруктураОтправителя = Новый Структура;
    СтруктураОтправителя.Вставить("name"  , "Bot");
    СтруктураОтправителя.Вставить("avatar", "");
    
    СтруктураПараметров  = Новый Структура;
    СтруктураПараметров.Вставить("sender", СтруктураОтправителя);
    СтруктураПараметров.Вставить("min_api_version", 1);
    
    Возврат СтруктураПараметров;
    
КонецФункции

Функция ТокенВЗаголовки(Знач Токен)
    
    СтруктураЗаголовков = Новый Соответствие;
    СтруктураЗаголовков.Вставить("X-Viber-Auth-Token", Токен);
    Возврат СтруктураЗаголовков;
    
КонецФункции

#КонецОбласти
