#pragma once

/// @file
/// @brief Определение типов данных VPN API
///
/// @copyright Copyright 2021 InfoTeCS.

#include <stdint.h>
#include <stddef.h>
#include <limits.h>
#include <time.h>

#if __unix__
#    include <unistd.h>
#elif defined( WIN32 ) || defined( WIN64 )
#    include <windows.h>
typedef int pid_t;
#endif

#if __has_include( <vpn_api/events.h> )
#    include <vpn_api/events.h>
#else
#    include "events.h"
#endif

// workaround for Apple
#ifndef LOGIN_NAME_MAX
#    define LOGIN_NAME_MAX 256
#endif

#ifndef NODE_NAME_MAX
#    define NODE_NAME_MAX 1024
#endif

#ifndef NET_NAME_MAX
#    define NET_NAME_MAX 1024
#endif

// workaround for Windows
#ifndef PATH_MAX
#    define PATH_MAX MAX_PATH
#endif

/// @brief Результат выполнения команды
typedef struct
{
    /// @brief Код возврата функций (0 - успешное завершение)
    uint32_t code;

    /// @brief Сообщение об ошибке (пустое при успешном завершении)
    /// @remarks Не требует освобождения памяти. Сообщение хранится до следующего вызова команды.
    const char* message;
} VpnApiReturnCode;

/// @brief Объект, описывающий текущее состояние VPN
typedef struct
{
    /// @brief Флаг установлены ли ключи
    bool isKeysInstalled;
    /// @brief Флаг включен ли VPN
    bool isVpnEnabled;
} VpnStatus;

/// @brief События VPN
enum VpnEvent
{
    Event_VpnServiceStarted,
    Event_VpnServiceStopped,
    Event_KeysInstalled,
    Event_KeysUninstalled,
    Event_VpnStarted,
    Event_VpnStopped,
    Event_NodesUpdated,
};

/// @brief Прикладные задачи и свойства узла
enum VpnNodeTask
{
    Task_Undefined = 0x0,
    Task_TrafficProtection = 0x1,
    Task_Coordinator = 0x2,
    Task_ActiveCoordinator = 0x4,
    Task_Client = 0x8,
    Task_MobileClient = 0x10,
    Task_LinuxClient = 0x20,
    Task_Connect = 0x40,
    Task_QssServer = 0x80,
    Task_QssPoint = 0x100,
    Task_QssPhone = 0x200,
    Task_GroupChatServer = 0x400,
    Task_PushServer = 0x800,
    Task_ConnectHub = 0x1000,
    Task_ConnectFileExchange = 0x2000,
    Task_NativeCoordinator = 0x4000,
    Task_BusinessMail = 0x8000,
};

/// @brief Битовая маска прикладных задач и свойств узла из VpnNodeTask
typedef uint32_t VpnNodeTasksMask;
/// @brief Все возможные типы узлов из VpnNodeTask

enum VpnNodeTasksMaskAll
{
    VPN_NODE_TASKS_MASK_ALL = UINT32_MAX
};

/// @brief Уровни привилегий пользователя
enum VpnPrivilege
{
    VpnPrivilegeUnknown = -1,
    VpnPrivilegeMin = 0,
    VpnPrivilegeMiddle = 1,
    VpnPrivilegeMax = 2,
    VpnPrivilegeSpecial = 3
};

/// @brief Информация об узле
typedef struct
{
    /// @brief Имя узла
    char* name;

    /// @brief ID узла
    uint32_t id;

    /// @brief IP узла
    uint32_t ip;

    /// @brief Битовая маска прикладных задач и свойств узла
    VpnNodeTasksMask tasksMask;
} VpnNodeInfo;

/// @brief Информация об пользователе
typedef struct
{
    /// @brief Имя пользователя
    char* name;

    /// @brief ID пользователя
    uint32_t id;

    /// @brief Количество связанных узлов
    uint32_t numNodes;

    /// @brief Список связанных узлов
    uint32_t* relatedNodes;
} VpnUserInfo;

/*! \addtogroup api_ver6 Функции SDK для версии 6 и выше
    @{
*/
/// @brief Информация об узле (расширенная версия)
typedef struct
{
    /// @brief Имя узла
    const char* name;
    /// @brief ID узла
    uint32_t id;
    /// @brief IP узла
    uint32_t ip;
    /// @brief ID сети
    uint16_t networkId;

    /// @brief Битовая маска прикладных задач и свойств узла
    VpnNodeTasksMask tasks;

    /// @brief Массив диапазонов туннелируемых данным узлом адресов IPv4
    struct
    {
        uint32_t startIp;
        uint32_t endIp;
    } * tunnels;
    /// @brief Размер массива диапазонов туннелируемых данным узлом адресов IPv4 (кол-во записей)
    size_t tunnelsSize;

    /// @brief Массив диапазонов туннелируемых данным узлом виртальных адресов IPv4
    struct
    {
        uint32_t startIp;
        uint32_t endIp;
    } * tunnelsVirtual;
    /// @brief Размер массива диапазонов туннелируемых данным узлом виртуальных адресов IPv4 (кол-во записей)
    size_t tunnelsVirtualSize;

    /// @brief ID координатора, за которым находится узел (0 - неизвестно)
    uint32_t coordinatorId;
    /// @brief Порт доступа для tcp-туннеля на координаторе (0 - отсутствует)
    uint16_t tcpTunnelPort;
    /// @brief Cвязь с узлом напрямую без участия координатора
    bool directLink;
    /// @brief Имеются симметричные ключи обмена с узлом
    bool haveKeys;

} VpnNodeInfoExt;

/*! @} */

/*! \addtogroup api_token_operations
    @{
*/
/// @brief Информация об устройстве аутентификации
typedef struct
{
    const char* label; ///< Метка устройства (устанавливается при инициализации)
    const char* manufacturer; ///< Производитель устройства
    const char* model;        ///< Модель устройства
    const char* serialNumber; ///< Серийный номер устройства

    uint32_t isLocked : 1; ///< Устройство заблокировано из-за превышения количества попыток аутентификации
    uint32_t isFinal : 1;  ///< Осталась последняя попыка аутентификации
    uint32_t isLow : 1; ///< Была как минимум одна неудачная попытка аутентификации
    uint32_t isDefault : 1; ///< Этот токен требуется для авторизации в сети  ViPNet
    /*! \addtogroup api_ver8
        @{
    */
    uint32_t isInitialized : 1;  ///< Токен проинициализирован
    uint32_t hasPin : 1;         ///< PIN-код пользователя установлен
    uint32_t writeProtected : 1; ///> Токен защищён от записи
    uint32_t reserved : 25;
    /*! @} */

    uint32_t maxPinLen; ///< Максимальная длина пин-кода
    uint32_t minPinLen; ///< Минимальная длина пин-кода
} VpnTokenInfo;

/// @brief Дескриптор устройства аутентификации
typedef void* VpnTokenHandle;
/*! @} */

#undef VIPNET_EVENT
#define VIPNET_EVENT( X, ... ) void ( *X )( __VA_ARGS__ );

/*! \addtogroup api_ver6
    @{
*/
/// @brief Таблица указателей на обработчики событий из EVENT_LIST (events.h)
typedef struct
{
    EVENT_LIST
} VpnEventHandlers;

/// @brief Список проверок DST (32)
// clang-format off
#define CHECK_DST_ITEMS( ITEM )                                                                                                     \
    ITEM( CheckDstLicenceExpired )         /*  Dst файл содержит истекшую лицензию */                                               \
    ITEM( CheckDstMobileTaskNotFound )     /*  В dst не найдена ПЗ Mobile для собственного узла */                                  \
    ITEM( CheckDstUnmergeError )           /*  Системная ошибка распаковки */                                                       \
    ITEM( CheckDstMalformedDst )           /*  Dst файл битый и не может быть распакован */                                         \
    ITEM( CheckDstTooManyWs )              /*  Слишком много связей в dst */                                                        \
    ITEM( CheckDstTooManyTunnels )         /*  Слишком много туннелей в dst */                                                      \
    ITEM( CheckDstWrongPassword )          /*  Указан неверный пароль */                                                            \
    ITEM( CheckDstWrongParams )            /*  В функцию распаковки переданы неверные параметры */                                  \
    ITEM( CheckDstTooBig )                 /*  Размер dst файла превышает максимально допустимый размер */                          \
    ITEM( CheckDstNoAccessIp )             /*  Отсутствуют ip-адреса доступа для активного координатора */                          \
    ITEM( CannotReadDnsTxt )               /*  Невозможно прочесть или обработать DNS.TXT */                                        \
    ITEM( DnsNoServerFound )               /*  Не заданы DNS */                                                                     \
    ITEM( DnsTooManyServers )              /*  Количество записей DNS серверов привышает допустимое */                              \
    ITEM( DnsZoneNotFound )                /*  Не заданы DNS-zone */                                                                \
    ITEM( DnsTooManyZones )                /*  Количество записей DNS зон привышает допустимое */                                   \
    ITEM( DnsAutoStartRuleNoFound )        /*  Не задан параметр настройки атостарта */                                             \
    ITEM( DnsConnectDemandNoFound )        /*  Не задан параметр настройки On Demand Connect */                                     \
    ITEM( ConfigNoSupported )              /*  Конфигурационный файл не поддерживается */                                           \
    ITEM( DnsFileTooBig )                  /*  Файл vpnconfig слишком большой */                                                    \
    ITEM( ConfigureValueIsEmpty )          /*  Не найден ни один параметр в конфигурационном файле */                               \
    ITEM( DnsConnectDemandNotAllowed )     /*  У пользователя не достаточно полномочий для включения ConnectOnDemand */             \
    ITEM( CheckAbTooManyDns )              /*  Количество доменных зон превышено допустимое количество */                           \
    ITEM( UnexpectedAlgServiceName )       /*  Недопустимое имя службы в настройках alg */                                          \
    ITEM( InvalidAlgServiceConfiguration ) /*  Невалидная конфигурация службы alg */                                                \
    ITEM( DnsZoneIncludesForbiddenAddr )   /*  Dns зоны включают в себя недопустимый адрес */                                       \
    ITEM( CheckDNSNameNumber )             /*  Количество DNS-имен координатора не должно быть более 5. */                          \
    ITEM( CheckDstPrivilegesLevelIsLow )   /*  Недостаточный уровень привиллегий для данного сценария */                            \
    ITEM( DnsInternalSystemError )         /*  Внутренняя системная ошибка */                                                       \
    ITEM( UnmergeDstBlocked )              /*  Разворачивание dst заблокировано из-за превышения количества неправильных паролей */ \
    ITEM( CheckDstAdPinBlocked )           /*  Разворачивание dst заблокировано из-за блокировки устройства аутентификации */       \
    ITEM( CheckDstAdPinFailed )            /*  Неверный пин-код */                                                                  \
    ITEM( CheckDstAdNotFound )             /* Указанное устройство аутентификации не найдено */

/// @brief Список ролей узла (59)
#define NODE_ROLES( ROLE )                                                                                    \
    ROLE( TASK_MAIL )                  /*  Деловая почта */                                                      \
    ROLE( TASK_NCC )                   /*  ЦУС */                                                                \
    ROLE( TASK_POLICY_MANAGER )        /*  Policy Manager (Центр управления политиками безопасности) */          \
    ROLE( TASK_MONITORING_SYSTEM )     /*  Система мониторинга */                                                \
    ROLE( TASK_MFTP )                  /*  MFTP */                                                               \
    ROLE( TASK_IP )                    /*  Защита трафика */                                                     \
    ROLE( TASK_IP_SERVER )             /*  Сервер IP-адресов (такой номер используется в базе ЦУСа) */           \
    ROLE( TASK_IP_PROXY )              /*  Сервер IP-адресов (такой номер попадает в справочники вместо 0018) */ \
    ROLE( TASK_PUBLIC_INTERNET )       /*  Сервер IP-адресов c функцией сервера Открытого Интернета */           \
    ROLE( TASK_CRYPTO_SERVICE )        /*  КриптоСервис */                                                       \
    ROLE( TASK_LINUX_FAILOVER )        /*  ViPNet Failover */                                                    \
    ROLE( TASK_VIPNET_SDK )            /*  ViPNet SDK */                                                         \
    ROLE( TASK_LINUX_WEB_GATE )        /*  Web-шлюз */                                                           \
    ROLE( TASK_VIPNET_U )              /*  Coordinator KB 1000 */                                                \
    ROLE( TASK_TERMINAL_NAVIGATOR )    /*  Терминал Навигатор */                                                 \
    ROLE( TASK_TERMINAL_SPECTR )       /*  Терминал Спектр */                                                    \
    ROLE( TASK_TERMINAL_AREAL )        /*  Терминал Ареал-Сервис */                                              \
    ROLE( TASK_ISU_MAGISTRAL )         /*  ИСУ Магистраль */                                                     \
    ROLE( TASK_ISU_NAVIGATOR )         /*  ИСУ Навигатор */                                                      \
    ROLE( TASK_ISU_SPECTR )            /*  ИСУ Спектр */                                                         \
    ROLE( TASK_MONITORING )            /*  АРМ мониторинга */                                                    \
    ROLE( TASK_ISU_VIDEOTON )          /*  ИСУ Видеотон */                                                       \
    ROLE( TASK_TERMINAL_UFS )          /*  Блок сопряжения УФС */                                                \
    ROLE( TASK_SGA_SERVER )            /*  Сервер SGA */                                                         \
    ROLE( TASK_SGA_CLIENT )            /*  Клиент SGA */                                                         \
    ROLE( TASK_TLS_SERVER )            /*  Сервер TLS */                                                         \
    ROLE( TASK_HW100_A )               /*  Coordinator HW100-A */                                                \
    ROLE( TASK_HW100_B )               /*  Coordinator HW100-B */                                                \
    ROLE( TASK_HW100_C )               /*  Coordinator HW100-C */                                                \
    ROLE( TASK_HW1000 )                /*  Coordinator HW1000 */                                                 \
    ROLE( TASK_HW2000 )                /*  Coordinator HW2000 */                                                 \
    ROLE( TASK_SDK_LINUX )             /*  КриптоСервис Linux */                                                 \
    ROLE( TASK_TERMINAL )              /*  ViPNet Terminal */                                                    \
    ROLE( TASK_HWVPNM )                /*  Coordinator HW-VPNM */                                                \
    ROLE( TASK_MONITORING_AGENT )      /*  Агент мониторинга СБ РФ */                                            \
    ROLE( TASK_CLIENT_MOBILE )         /*  VPN-клиент для мобильных устройств */                                 \
    ROLE( TASK_VSG )                   /*  ViPNet Security Gateway (Coordinator HW/VA)2 */                       \
    ROLE( TASK_HWVA )                  /*  Coordinator HW-VA3 */                                                 \
    ROLE( TASK_HW10 )                  /*  Coordinator HW10 */                                                   \
    ROLE( TASK_HWMCM )                 /*  Coordinator HW-MCM */                                                 \
    ROLE( TASK_HW100_D )               /*  Coordinator HW100D */                                                 \
    ROLE( TASK_CONNECT )               /*  Client Connect */                                                     \
    ROLE( TASK_HW50_A )                /*  Coordinator HW50A */                                                  \
    ROLE( TASK_HW50_B )                /*  Coordinator HW50B */                                                  \
    ROLE( TASK_HW500 )                 /*  Coordinator HW500 */                                                  \
    ROLE( TASK_HW1000_C )              /*  Coordinator HW1000C */                                                \
    ROLE( TASK_HW1000_D )              /*  Coordinator HW1000D */                                                \
    ROLE( TASK_HW5000 )                /*  Coordinator HW5000 */                                                 \
    ROLE( TASK_IG10 )                  /*  Coordinator IG10 */                                                   \
    ROLE( TASK_SHW1000 )               /*  Coordinator SHW100 */                                                 \
    ROLE( TASK_SHW2000 )               /*  Coordinator SHW2000 */                                                \
    ROLE( TASK_SHWVA )                 /*  Coordinator SHWVA */                                                  \
    ROLE( TASK_IG10_A0 )               /*  Coordinator IG10A0 */                                                 \
    ROLE( TASK_IG10_A1 )               /*  Coordinator IG10A1 */                                                 \
    ROLE( TASK_IG10_B0 )               /*  Coordinator G10B0 */                                                  \
    ROLE( TASK_IG10_B1 )               /*  Coordinator IG10B1 */                                                 \
    ROLE( TASK_LINUX_CLIENT )          /*  VPN-клиент для устройств на ОС Linux */                               \
    ROLE( TASK_CONNECT_HUB )           /*  VPN-клиент для сервера Connect */                                     \
    ROLE( TASK_CONNECT_FILE_EXCHANGE ) /*  Connect для обмена файлами */

/// @brief Роли узла
/// @details Битовые поля с именами из списка NODE_ROLES: 1 - роль присутствует, 0 - роль отсутвует
typedef struct
{
#define AS_BIT_FIELD( field ) size_t field : 1;
    NODE_ROLES( AS_BIT_FIELD )
#undef AS_BIT_FIELD
} VpnNodeTasksExt;

/// @brief Статус проверки DST
/// @details Битовые поля с именами из списка CHECK_DST_ITEMS: 1 - проверка не прошла, 0 - проверка прошла
typedef struct
{
#define AS_BIT_FIELD( field ) size_t field : 1;
    CHECK_DST_ITEMS( AS_BIT_FIELD )
#undef AS_BIT_FIELD
} VpnDstStatus;

/// @brief Информация о ключевом дистрибутиве (DST)
typedef struct
{
    char nodeName[NODE_NAME_MAX]; ///> Имя узла
    uint32_t nodeId;              ///> ID узла
    enum VpnPrivilege privileges;      ///> Привилегии

    time_t licenseExpired;  ///> Дата истечения лицензии
    time_t licenseIssued;   ///> Дата выдачи dst

    size_t logonDevice : 1; ///> Требуется устройство аутентификации
    size_t password : 1;    ///> Для расшифровки резрвных ключей нужен пароль

    VpnDstStatus errors;    ///> Результат проверки DST
} VpnDstInfo;

///@brief Данные о состоянии и режиме работы службы
typedef struct
{
    char version[20];          ///> Версия ПО (MJR.MNR.SUB-BUILD)
    char user[LOGIN_NAME_MAX]; ///> Имя пользователя ОС, для которого запущен сервис
    char workdir[PATH_MAX];    ///> Путь к файлам текущей конфигурации

    int vpnStatus;  ///> Текущий режим VPN-тоннеля (0 - выкл, 1 - вкл, 2 - рассинронизация, 3 - соединение проверено)
    time_t vpnTime; ///> Время сети

    pid_t pid;      ///> PID сервиса

    int logLevel;   ///> Уровень детализации логов ( 0 - крит, 1 - ошибки, 2 - нотификации, 3 - информация, 4 - отладка, 5,6,10,11 - детальная

    int keysStatus;    ///> Текущий статус ключевой конфигурации (0 - нет, 1 - проверена, 2 - недействительна)
    time_t keysIssued; ///> Дата/время выпуска DST

    int licenseStatus;     ///> Статус проверки лицензии (0 - действительна, 1 - повреждена, 2 - истекла, 3 - ошибочная датировка, 4 - отсутсвует, 13 - неограниченная, [5-12] - действительна, но истекает через [1-7] дней )
    time_t licenseExpired; ///> Дата/время истечения лицензии
    time_t licenseIssued;  ///> Дата/время выпуска лицензии

    size_t loginType : 3;           ///> Тип аутентификации (0 - не определён, 1 - пароль, 2 - "пароль на устройстве", 4 - "ключ на устройстве")
    size_t loginCounterUser : 1;    ///> Флаг аутентификаций пользователя (по пароолю): 1 - разрешена, 0 - заблокирована
    size_t loginCounterAdmin : 1;   ///> Флаг аутентификаций администратора: 1 - разрешена, 0 - заблокирована

    size_t configUpdated : 1;       ///> Флаг валидности конфигурационных файлов и БД после обновления ПО: 1 - валидна, 0 - невалидна

    size_t integrityLicense : 1;    ///> Результат проверки контрольных сумм лицензии: 1 - не нарушена, 0 - нарушена
    size_t integrityHostlinks : 1;  ///> Результат проверки контрольных сумм справочников: 1 - не нарушена, 0 - нарушена
    size_t integrityConfigs : 1;    ///> Результат проверки контрольных сумм других конфигурационных файлов: 1 - не нарушена, 0 - нарушена

    size_t autorunShell : 1;        ///> Флаг настройки автозапуска при логине в консоли: 1- вкл, 0 - откл.
    size_t autorunDesktop : 1;      ///> Флаг настройки автозапуска при логине в графическом интерфейсе: 1- вкл, 0 - откл.

    int dnsState;                   ///> Текущий статус подситемы DNS: 0 - вкл, 1 - выкл, 2 - выкл (нет iptables), 3 - выкл (нет loopback)
    int faultTolerance;             ///> Количество попыток восстановления (-1 - отключено, INT_MAX - включено и не ограничено)

    uint32_t nodeId;                ///> Идентификатор узла
    uint16_t networkId;             ///> Идентификатор сети
    char nodeName[NODE_NAME_MAX];   ///> Имя узла
    char networkName[NET_NAME_MAX]; ///> Имя сети

    enum VpnPrivilege privileges;        ///> Уровень полномочий
    VpnNodeTasksExt tasks;          ///> Роли

    uint32_t coordinatorId;              ///> Идентификатор сервера соединений
    uint32_t coordinatorIp;              ///> IPv4 адрес сервера соединений
    char coordinatorName[NODE_NAME_MAX]; ///> Имя сервера соединений

    char cipher[16]; ///> Криптографический алгоритм ("gost", "c-aes", "t-fips", "fips", "magma", "kuznyechik")

} VpnUltimateStatus;

///@brief Результат проверки работоспособности
typedef struct
{
    size_t environment : 1;  ///> Нарушена целостность исполняемых файлов
    size_t integrity : 1;    ///> Нарушена целостность конфигурационных файлов
    size_t cryptography : 1; ///> Ошибки при диагностике CSP
} VpnHealthStatus;


/// @brief Параметры инициализации
typedef struct
{
    const char* key;   ///> Зарезервированные ключи
    void* value;
} VpnApiInitData;

/// @brief Уровни логирования
enum LoggerLevel
{
    LOG_CRIT     = 0, ///> критические ошибки
    LOG_ERR      = 1, ///> ошибки
    LOG_NOTICE   = 2, ///> нотификации
    LOG_INFO     = 3, ///> информация
    LOG_DEBUG    = 4, ///> отладочные данные
    LOG_DEEP     = 5, ///> остальные уровни используются для детального вывода
    LOG_DEEPER   = 6,
    LOG_GARBAGE  = 10,
    LOG_PARANOID = 11
};

// clang-format on
/*! @} */
