#pragma once

/// @file
/// @brief Define the VPN API data types
///
/// @copyright Copyright 2021 InfoTeCS.

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

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

#ifndef NODE_NAME_MAX
#    define NODE_NAME_MAX 1024
#endif

#ifndef NET_NAME_MAX
#    define NET_NAME_MAX 1024
#endif

/// @brief Command execution result
typedef struct
{
    /// @brief Function output code (0 - success)
    uint32_t code;

    /// @brief Error message (blank if success)
    /// @remarks Does not require the memory release. The message is stored till the next command call.
    const char* message;
} VpnApiReturnCode;

/// @brief Current VPN state object
typedef struct
{
    /// @brief Whether keys are installed
    bool isKeysInstalled;
    /// @brief Whether VPN is on
    bool isVpnEnabled;
} VpnStatus;

/// @brief VPN events
enum VpnEvent
{
    Event_VpnServiceStarted,
    Event_VpnServiceStopped,
    Event_KeysInstalled,
    Event_KeysUninstalled,
    Event_VpnStarted,
    Event_VpnStopped,
    Event_NodesUpdated,
    Event_VpnBeginStarting,
    Event_VpnBeginStopping,
};

/// @brief Host roles and properties
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 Bit mask of the host roles and properties from VpnNodeTask
typedef uint32_t VpnNodeTasksMask;
/// @brief All possible host types from VpnNodeTask

enum VpnNodeTasksMaskAll
{
    VPN_NODE_TASKS_MASK_ALL = UINT32_MAX
};

/// @brief User permission levels
enum VpnPrivilege
{
    VpnPrivilegeUnknown = -1,
    VpnPrivilegeMin = 0,
    VpnPrivilegeMiddle = 1,
    VpnPrivilegeMax = 2,
    VpnPrivilegeSpecial = 3
};

/// @brief Host details
typedef struct
{
    /// @brief Host name
    char* name;

    /// @brief Host ID
    uint32_t id;

    /// @brief Host IP
    uint32_t ip;

    /// @brief Bit mask of the host roles and properties
    VpnNodeTasksMask tasksMask;
} VpnNodeInfo;

/// @brief User details
typedef struct
{
    /// @brief User name
    char* name;

    /// @brief User ID
    uint32_t id;

    /// @brief Number of the linked hosts
    uint32_t numNodes;

    /// @brief List of the linked hosts
    uint32_t* relatedNodes;
} VpnUserInfo;

/*! \addtogroup api_ver6 SDK functions for version 6 and higher
    @{
*/
/// @brief Host details (extended)
typedef struct
{
    /// @brief Host name
    const char* name;
    /// @brief Host ID
    uint32_t id;
    /// @brief Host IP
    uint32_t ip;
    /// @brief Network ID
    uint16_t networkId;

    /// @brief Bit mask of the host roles and properties
    VpnNodeTasksMask tasks;

    /// @brief Array of IPv4 addresses tunneled by this host
    struct
    {
        uint32_t startIp;
        uint32_t endIp;
    } * tunnels;
    /// @brief Size of the array of IPv4 addresses tunneled by this host (number of entries)
    size_t tunnelsSize;

    /// @brief Array of the virtual IPv4 addresses tunneled by this host
    struct
    {
        uint32_t startIp;
        uint32_t endIp;
    } * tunnelsVirtual;
    /// @brief Size of the array of the virtual IPv4 addresses tunneled by this host (number of entries)
    size_t tunnelsVirtualSize;

    /// @brief ID of the coordinator behind which the host is located (0 - unknown)
    uint32_t coordinatorId;
    /// @brief Coordinator's access port for TCP tunnel (0 - N/A)
    uint16_t tcpTunnelPort;
    /// @brief Direct host connection bypassing the coordinator
    bool directLink;
    /// @brief Symmetric host exchange keys are available
    bool haveKeys;

} VpnNodeInfoExt;

/*! @} */

/*! \addtogroup api_token_operations
    @{
*/
/// @brief Logon device details
typedef struct
{
    const char* label;        ///< Device label (set on initialization)
    const char* manufacturer; ///< Device manufacturer
    const char* model;        ///< Device model
    const char* serialNumber; ///< Device serial number

    uint32_t isLocked : 1;  ///< Device locked due to exceeded logon attempts
    uint32_t isFinal : 1;   ///< Last loogn attempt left
    uint32_t isLow : 1;     ///< There was at least one unsuccessful logon attempt
    uint32_t isDefault : 1; ///< This token is required to log on to the ViPNet network
    /*! \addtogroup api_ver8
        @{
    */
    uint32_t isInitialized : 1;  ///< Token initialized
    uint32_t hasPin : 1;         ///< User PIN set
    uint32_t writeProtected : 1; ///> Token is write-protected
    uint32_t reserved : 25;
    /*! @} */

    uint32_t maxPinLen; ///< Maximum PIN length
    uint32_t minPinLen; ///< Minimum PIN length
} VpnTokenInfo;

/// @brief Logon device handle
typedef void* VpnTokenHandle;
/*! @} */

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

/*! \addtogroup api_ver6
    @{
*/
/// @brief Pointers to the event handlers from EVENT_LIST (events.h)
typedef struct
{
    EVENT_LIST
} VpnEventHandlers;

/// @brief DST checklist (32)
// clang-format off
#define CHECK_DST_ITEMS( ITEM )                                                                                                     \
    ITEM( CheckDstLicenceExpired )         /*  Dst file contains an expired license */                                               \
    ITEM( CheckDstMobileTaskNotFound )     /*  Your dst file has no Mobile role */                                  \
    ITEM( CheckDstUnmergeError )           /*  System error while unpacking */                                                       \
    ITEM( CheckDstMalformedDst )           /*  Dst file corrupt and cannot be unpacked */                                         \
    ITEM( CheckDstTooManyWs )              /*  Too many links in dst file */                                                        \
    ITEM( CheckDstTooManyTunnels )         /*  Too many tunneled IP addresses in dst file */                                                      \
    ITEM( CheckDstWrongPassword )          /*  Wrong password */                                                            \
    ITEM( CheckDstWrongParams )            /*  Invalid parameters passed to the unpack function */                                  \
    ITEM( CheckDstTooBig )                 /*  Dst file exceeds the maximum size */                          \
    ITEM( CheckDstNoAccessIp )             /*  No access IP address for an active coordinator */                          \
    ITEM( CannotReadDnsTxt )               /*  Cannot read or process DNS.TXT */                                        \
    ITEM( DnsNoServerFound )               /*  DNS server not specified */                                                                     \
    ITEM( DnsTooManyServers )              /*  Too many DNS server entries */                              \
    ITEM( DnsZoneNotFound )                /*  DNS zones not set */                                                                \
    ITEM( DnsTooManyZones )                /*  Too many DNS zone entries */                                   \
    ITEM( DnsAutoStartRuleNoFound )        /*  The autostart feature not configured */                                             \
    ITEM( DnsConnectDemandNoFound )        /*  The On Demand Connect feature not configured */                                     \
    ITEM( ConfigNoSupported )              /*  Configuration file not supported */                                           \
    ITEM( DnsFileTooBig )                  /*  The vpnconfig file is too large */                                                    \
    ITEM( ConfigureValueIsEmpty )          /*  No parameter found in the configuration file */                               \
    ITEM( DnsConnectDemandNotAllowed )     /*  User has insufficient permissions to turn on ConnectOnDemand */             \
    ITEM( CheckAbTooManyDns )              /*  Too many DNS zones */                           \
    ITEM( UnexpectedAlgServiceName )       /*  Invalid service name in the alg settings */                                          \
    ITEM( InvalidAlgServiceConfiguration ) /*  Invalid alg configuration */                                                \
    ITEM( DnsZoneIncludesForbiddenAddr )   /*  DNS zone include invalid address */                                       \
    ITEM( CheckDNSNameNumber )             /*  Coordinator cannot have more than 5 DNS names. */                          \
    ITEM( CheckDstPrivilegesLevelIsLow )   /*  Insufficient permission level to complete the operation */                            \
    ITEM( DnsInternalSystemError )         /*  Internal system error */                                                       \
    ITEM( UnmergeDstBlocked )              /*  Cannot unpack dst file due to too many wrong passwords */ \
    ITEM( CheckDstAdPinBlocked )           /*  Cannot unpack dst file due to the logon device lock */       \
    ITEM( CheckDstAdPinFailed )            /*  Wrong PIN */                                                                  \
    ITEM( CheckDstAdNotFound )             /* The specified logon device not found */

/// @brief Host roles (59)
#define NODE_ROLES( ROLE )                                                                                    \
    ROLE( TASK_MAIL )                  /*  Business Mail */                                                      \
    ROLE( TASK_NCC )                   /*  Network Control Center */                                                                \
    ROLE( TASK_POLICY_MANAGER )        /*  Policy Manager (Policy Management Center) */          \
    ROLE( TASK_MONITORING_SYSTEM )     /*  Monitoring System */                                                \
    ROLE( TASK_MFTP )                  /*  MFTP */                                                               \
    ROLE( TASK_IP )                    /*  Traffic protection */                                                     \
    ROLE( TASK_IP_SERVER )             /*  IP address server (number used in the NCC database) */           \
    ROLE( TASK_IP_PROXY )              /*  IP address server (number added to the host links instead of 0018) */ \
    ROLE( TASK_PUBLIC_INTERNET )       /*  IP address server with the Secure Internet Access feature */           \
    ROLE( TASK_CRYPTO_SERVICE )        /*  CryptoService */                                                       \
    ROLE( TASK_LINUX_FAILOVER )        /*  ViPNet Failover */                                                    \
    ROLE( TASK_VIPNET_SDK )            /*  ViPNet SDK */                                                         \
    ROLE( TASK_LINUX_WEB_GATE )        /*  Web Gate */                                                           \
    ROLE( TASK_VIPNET_U )              /*  Coordinator KB 1000 */                                                \
    ROLE( TASK_TERMINAL_NAVIGATOR )    /*  Terminal Navigator */                                                 \
    ROLE( TASK_TERMINAL_SPECTR )       /*  Terminal Spectr */                                                    \
    ROLE( TASK_TERMINAL_AREAL )        /*  Terminal Areal */                                              \
    ROLE( TASK_ISU_MAGISTRAL )         /*  ERP Magistral */                                                     \
    ROLE( TASK_ISU_NAVIGATOR )         /*  ERP Navigator */                                                      \
    ROLE( TASK_ISU_SPECTR )            /*  ERP Spectr */                                                         \
    ROLE( TASK_MONITORING )            /*  Monitoring client */                                                    \
    ROLE( TASK_ISU_VIDEOTON )          /*  ERP Videoton */                                                       \
    ROLE( TASK_TERMINAL_UFS )          /*  Signal coupler */                                                \
    ROLE( TASK_SGA_SERVER )            /*  SGA server */                                                         \
    ROLE( TASK_SGA_CLIENT )            /*  SGA client */                                                         \
    ROLE( TASK_TLS_SERVER )            /*  TLS server */                                                         \
    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 )             /*  CryptoService Linux */                                                 \
    ROLE( TASK_TERMINAL )              /*  ViPNet Terminal */                                                    \
    ROLE( TASK_HWVPNM )                /*  Coordinator HW-VPNM */                                                \
    ROLE( TASK_MONITORING_AGENT )      /*  Sberbank of Russia monitoring agent */                                            \
    ROLE( TASK_CLIENT_MOBILE )         /*  VPN client for mobile devices */                                 \
    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 client for Linux devices */                               \
    ROLE( TASK_CONNECT_HUB )           /*  VPN client for Connect server*/                                     \
    ROLE( TASK_CONNECT_FILE_EXCHANGE ) /*  Connect for file exchange */

/// @brief Host roles
/// @details Bit fields with names from the NODE_ROLES list: 1 - role added, 0 - role not added
typedef struct
{
#define AS_BIT_FIELD( field ) size_t field : 1;
    NODE_ROLES( AS_BIT_FIELD )
#undef AS_BIT_FIELD
} VpnNodeTasksExt;

/// @brief DST check status
/// @details Bit fields with  names from the CHECK_DST_ITEMS list: 1 - check failed, 0 - check succeeded
typedef struct
{
#define AS_BIT_FIELD( field ) size_t field : 1;
    CHECK_DST_ITEMS( AS_BIT_FIELD )
#undef AS_BIT_FIELD
} VpnDstStatus;

/// @brief Key set (DST) details
typedef struct
{
    char nodeName[NODE_NAME_MAX]; ///> Host name
    uint32_t nodeId;              ///> Host ID
    enum VpnPrivilege privileges;      ///> Permissions

    time_t licenseExpired;  ///> License expiration date
    time_t licenseIssued;   ///> Dst issue date

    size_t logonDevice : 1; ///> Logon device required
    size_t password : 1;    ///> Password required for decryption of the backup key set

    VpnDstStatus errors;    ///> DST check result
} VpnDstInfo;

/// @brief Service status and mode
typedef struct
{
    char version[20];          ///> Software version (MJR.MNR.SUB-BUILD)
    char user[LOGIN_NAME_MAX]; ///> Name of the OS user having started the service
    char workdir[PATH_MAX];    ///> Path to the current configuration files

    int vpnStatus;  ///> Current VPN tunnel mode (0 - off, 1 - on, 2 - not synced, 3 - connection checked)
    time_t vpnTime; ///> VPN time

    pid_t pid;      ///> Service PID

    int logLevel;   ///> Event severity level ( 0 - critical, 1 - errors, 2 - notifications, 3 - information, 4 - debug, 5,6,10,11 - deep debug)

    int keysStatus;    ///> Current status of the key configuration (0 - N/A, 1 - checked, 2 - invalid)
    time_t keysIssued; ///> DST issue date/time

    int licenseStatus;     ///> License check status (0 - valid, 1 - corrupt, 2 - expired, 3 - wrong dates, 4 - N/A, 13 - perpetual, [5-12] - valid but expires in [0-7] days )
    time_t licenseExpired; ///> License expiration date/time
    time_t licenseIssued;  ///> License issue date/time

    size_t loginType : 3;           ///> Logon method (0 - unknown, 1 - password, 2/4 - device)
    size_t loginCounterUser : 1;    ///> User logon flag (password): 1 - allowed, 0 - blocked
    size_t loginCounterAdmin : 1;   ///> Administrator logon flag: 1 - allowed, 0 - blocked

    size_t configUpdated : 1;       ///> Whether configuration files and database are valid after software update: 1 - valid, 0 - invalid

    size_t integrityLicense : 1;    ///> License checksum verification result: 1 - match, 0 - mismatch
    size_t integrityHostlinks : 1;  ///> Host links checksum verification result: 1 - match, 0 - mismatch
    size_t integrityConfigs : 1;    ///> Other configuration files' checksum verification result: 1 - match, 0 - mismatch

    size_t autorunShell : 1;        ///> Autostart on logon via the console shell: 1 - on, 0 - off
    size_t autorunDesktop : 1;      ///> Autostart on logon via the graphic shell: 1 - on, 0 - off

    int dnsState;                   ///> Current DNS subsystem status: 0 - on, 1 - off, 2 - off (no iptables), 3 - off (no loopback)
    int faultTolerance;             ///> Restore attempts count (-1 - off, INT_MAX - and and unlimited)

    uint32_t nodeId;                ///> Host ID
    uint16_t networkId;             ///> Network ID
    char nodeName[NODE_NAME_MAX];   ///> Host name
    char networkName[NET_NAME_MAX]; ///> Network name

    enum VpnPrivilege privileges;        ///> Permission level
    VpnNodeTasksExt tasks;          ///> Roles

    uint32_t coordinatorId;              ///> Connection server ID
    uint32_t coordinatorIp;              ///> IPv4 address of the connection server
    char coordinatorName[NODE_NAME_MAX]; ///> Connection server name

    char cipher[16]; ///> Encryption algorithm (see the possible values in the Developer's Guide)

} VpnUltimateStatus;

/// @brief Health check result
typedef struct
{
    size_t environment : 1;  ///> Integrity status of the executable files (1 - successful, 0 - unsuccessful)
    size_t integrity : 1;    ///> Integrity status of the configuration files (1 - successful, 0 - unsuccessful)
    size_t cryptography : 1; ///> CSP diagnostic status (1 - successful, 0 - unsuccessful)
} VpnHealthStatus;

/// @brief User traffic block status
enum VpnUserTrafficBlockStatus
{
    /// @brief User traffic is not blocked
    UserTrafficNotBlocked = 0,
    /// @brief User traffic is blocked
    UserTrafficBlocked = 1
};

/// @brief User traffic block information
typedef struct
{
    /// @brief User traffic block status
    enum VpnUserTrafficBlockStatus status;
    /// @brief User traffic blocking process name
    const char* processName;
} VpnUserTrafficBlockInfo;

/// @brief Configuration reference book information
typedef struct
{
    /// @brief Configuration reference book name
    const char* name;
} VpnRefBookInfo;

/// @brief Configuration reference book list information
typedef struct
{
    /// @brief Configuration reference book list
    VpnRefBookInfo* list;
    /// @brief Configuration reference book list size
    uint32_t size;
} VpnRefBookListInfo;

/// @brief Initialization settings
typedef struct
{
    const char* key;   ///> Reserved keywords
    void* value;
} VpnApiInitData;

/// @brief Event severity levels
enum LoggerLevel
{
    LOG_CRIT     = 0, ///> critical errors
    LOG_ERR      = 1, ///> errors
    LOG_NOTICE   = 2, ///> notifications
    LOG_INFO     = 3, ///> information
    LOG_DEBUG    = 4, ///> debug
    LOG_DEEP     = 5, ///> deep debug (this level and all others)
    LOG_DEEPER   = 6,
    LOG_GARBAGE  = 10,
    LOG_PARANOID = 11
};

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