/****************************************************************************
 *    Copyright (C) 2017-2020 Savoir-faire Linux Inc.                       *
 *   Author: Nicolas Jäger <nicolas.jager@savoirfairelinux.com>             *
 *   Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>           *
 *                                                                          *
 *   This library is free software; you can redistribute it and/or          *
 *   modify it under the terms of the GNU Lesser General Public             *
 *   License as published by the Free Software Foundation; either           *
 *   version 2.1 of the License, or (at your option) any later version.     *
 *                                                                          *
 *   This library is distributed in the hope that it will be useful,        *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of         *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU      *
 *   Lesser General Public License for more details.                        *
 *                                                                          *
 *   You should have received a copy of the GNU General Public License      *
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.  *
 ***************************************************************************/
#pragma once

#include "profile.h"

#include "typedefs.h"

#include <memory>

#include <QString>

namespace lrc
{

namespace api
{

class ContactModel;
class ConversationModel;
class NewCallModel;
class NewAccountModel;
class NewDeviceModel;
class NewCodecModel;
class PeerDiscoveryModel;

namespace account
{
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
Q_NAMESPACE
Q_CLASSINFO("RegisterEnumClassesUnscoped", "false")
#endif

enum class Type {
    INVALID,
    RING,
    SIP
};
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
Q_ENUM_NS(Type)
#endif

#pragma push_macro("REGISTERED")
#undef REGISTERED

enum class Status {
    INVALID,
    ERROR_NEED_MIGRATION,
    INITIALIZING,
    UNREGISTERED,
    TRYING,
    REGISTERED
};
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
Q_ENUM_NS(Status)
#endif

static inline account::Status
to_status(const QString& type)
{
    if (type == "INITIALIZING")
        return account::Status::INITIALIZING;
    else if (type == "UNREGISTERED")
        return account::Status::UNREGISTERED;
    else if (type == "TRYING")
        return account::Status::TRYING;
    else if (type == "REGISTERED" || type == "READY")
        return account::Status::REGISTERED;
    else if (type == "ERROR_NEED_MIGRATION")
        return account::Status::ERROR_NEED_MIGRATION;
    else
        return account::Status::INVALID;
}

#pragma pop_macro("REGISTERED")

enum class KeyExchangeProtocol {
    NONE,
    SDES
};
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
Q_ENUM_NS(KeyExchangeProtocol)
#endif

enum class TlsMethod {
    DEFAULT,
    TLSv1,
    TLSv1_1,
    TLSv1_2
};
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
Q_ENUM_NS(TlsMethod)
#endif

struct ConfProperties_t {
    QString                                           mailbox;
    QString                                           dtmfType;
    bool                                              autoAnswer;
    bool                                              isRendezVous;
    int                                               activeCallLimit;
    QString                                           hostname;
    QString                                           username;
    QString                                           routeset;
    QString                                           password;
    QString                                           realm;
    QString                                           localInterface;
    QString                                           deviceId;
    QString                                           deviceName;
    QString                                           managerUri;
    QString                                           managerUsername;
    bool                                              publishedSameAsLocal;
    int                                               localPort;
    int                                               publishedPort;
    QString                                           publishedAddress;
    QString                                           userAgent;
    bool                                              upnpEnabled;
    bool                                              hasCustomUserAgent;
    bool                                              allowIncoming;
    QString                                           archivePassword;
    bool                                              archiveHasPassword;
    QString                                           archivePath;
    QString                                           archivePin;
    bool                                              proxyEnabled;
    QString                                           proxyServer;
    QString                                           proxyPushToken;
    bool                                              peerDiscovery;
    bool                                              accountDiscovery;
    bool                                              accountPublish;
    int                                               registrationExpire;
    VectorMapStringString                             credentials;
    struct Audio_t {
        int                                           audioPortMax;
        int                                           audioPortMin;
    } Audio;
    struct Video_t {
        bool                                          videoEnabled;
        int                                           videoPortMax;
        int                                           videoPortMin;
    } Video;
    struct STUN_t {
        QString                                       server;
        bool                                          enable;
    } STUN;
    struct TURN_t {
        QString                                       server;
        bool                                          enable;
        QString                                       username;
        QString                                       password;
        QString                                       realm;
    } TURN;
    struct Presence_t {
        bool                                          presencePublishSupported;
        bool                                          presenceSubscribeSupported;
        bool                                          presenceEnabled;
    } Presence;
    struct Ringtone_t {
        QString                                       ringtonePath;
        bool                                          ringtoneEnabled;
    } Ringtone;
    struct SRTP_t {
        KeyExchangeProtocol                           keyExchange;
        bool                                          enable;
        bool                                          rtpFallback;
    } SRTP;
    struct TLS_t {
        int                                           listenerPort;
        bool                                          enable;
        int                                           port;
        QString                                       certificateListFile;
        QString                                       certificateFile;
        QString                                       privateKeyFile;
        QString                                       password;
        TlsMethod                                     method;
        QString                                       ciphers;
        QString                                       serverName;
        bool                                          verifyServer;
        bool                                          verifyClient;
        bool                                          requireClientCertificate;
        int                                           negotiationTimeoutSec;
    } TLS;
    struct DHT_t {
        int                                           port;
        bool                                          PublicInCalls;
        bool                                          AllowFromTrusted;
    } DHT;
    struct RingNS_t {
        QString                                       uri;
        QString                                       account;
    } RingNS;
    struct Registration_t {
        int                                           expire;
    } Registration;

    MapStringString                                   toDetails() const;
};

// Possible account export status
enum class ExportOnRingStatus {
    SUCCESS = 0,
    WRONG_PASSWORD = 1,
    NETWORK_ERROR = 2,
    INVALID
};
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
Q_ENUM_NS(ExportOnRingStatus)
#endif

enum class RegisterNameStatus {
    SUCCESS = 0,
    WRONG_PASSWORD = 1,
    INVALID_NAME = 2,
    ALREADY_TAKEN = 3,
    NETWORK_ERROR = 4,
    INVALID
};
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
Q_ENUM_NS(RegisterNameStatus)
#endif

enum class LookupStatus {
    SUCCESS = 0,
    INVALID_NAME = 1,
    NOT_FOUND = 2,
    ERROR = 3,
    INVALID
};
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
Q_ENUM_NS(LookupStatus)
#endif

struct Info
{
    bool freeable = false;
    bool valid = true;
    QString registeredName;
    Status status = account::Status::INVALID;
    std::unique_ptr<lrc::api::ContactModel> contactModel;
    std::unique_ptr<lrc::api::ConversationModel> conversationModel;
    std::unique_ptr<lrc::api::NewCallModel> callModel;
    std::unique_ptr<lrc::api::NewDeviceModel> deviceModel;
    std::unique_ptr<lrc::api::NewCodecModel> codecModel;
    std::unique_ptr<lrc::api::PeerDiscoveryModel> peerDiscoveryModel;
    NewAccountModel* accountModel{ nullptr };

    // daemon config
    QString                 id;
    profile::Info           profileInfo; // contains: type, alias
    bool                    enabled;
    ConfProperties_t        confProperties;

    // load/save
    void                    fromDetails(const MapStringString& details);
};

} // namespace account
} // namespace api
} // namespace lrc
