#ifndef ROCKETCHAT_H
#define ROCKETCHAT_H

#include <QString>
#include <QObject>
#include <QSharedPointer>
#include <QHash>
#include <QMap>
#include <QSharedPointer>
#include <string>
#include <fstream>
#include <streambuf>
#include <QGuiApplication>
#include <QtConcurrent>

#include "rocketchatserver.h"
#include "api/restapi.h"
#include "api/meteorddp.h"
#include "repos/entities/rocketchatuser.h"
#include "persistancelayer.h"
#include "ddpRequests/pingrequest.h"
#include "ddpRequests/ddpmethodrequest.h"
#include "ddpRequests/ddpsubscriptionrequest.h"
#include "ddpRequests/rocketchatsubscribechannelrequest.h"
#include "ddpRequests/rocketchatcreatepublicgrouprequest.h"

#include "CustomModels/loginmethodsmodel.h"

#include "notifications/notifications.h"

#ifdef Q_OS_IOS

#endif

#ifdef Q_OS_ANDROID
#include "android/androidfiledialog.h"
#include "android/androidstatusbarcolor.h"
#include "android/androidcookies.h"
#endif



using namespace std;
class RocketChat : public QObject
{
        Q_OBJECT
        Q_PROPERTY( int userStatus READ getUserStatus NOTIFY userStatusChanged )

    public:
        explicit RocketChat( QGuiApplication *mApp );
        ~RocketChat();

        //TODO: check for depricated methods
        Q_INVOKABLE void uploadFile( const QString &pChannelId, const QString &pPath );
        Q_INVOKABLE void uploadVideo( const QString &pChannelId, const QString &pPath );
        Q_INVOKABLE bool newServerByDomain( const QString &pChannelId, bool pUnsecure );
        Q_INVOKABLE bool getDdpConnectionEstablished() const;

        Q_INVOKABLE void getFileRessource( const QString &pUrl );
        Q_INVOKABLE void getFileRessource( const QString &pUrl, const QString &pType );

        Q_INVOKABLE void cancelUpload( const QString &pServerId, const QString &pFileId );

        Q_INVOKABLE void joinChannel( const QString &pServer, const QString &pChannelId );
        Q_INVOKABLE void joinChannelByNameAndType( const QString &pServerId, const QString &pChannelName, const QString &pType );

        Q_INVOKABLE void login( const QString &pServerId, const QString &pUsername,
                                const QString &pPassword );
        Q_INVOKABLE void loginWithSamlToken( const QString &pToken );
        Q_INVOKABLE void loginWithMethod( const QString &method, const QString &payload );
        Q_INVOKABLE void openPrivateChannelWith( const QString &pServerId, const QString &pUsername );
        Q_INVOKABLE void sendMessage( const QString &pServerId, const QString &pChannelId,
                                      const QString &pMessage );
        Q_INVOKABLE void openFileDialog( const QString &pChannelId );
        Q_INVOKABLE void logout( const QString &pServer );
        Q_INVOKABLE void createPublicGroup( const QString &pServerId, const QString &pChannelName,
                                            const QStringList &pUsersNames, bool pReadonly = false );
        Q_INVOKABLE void createPrivateGroup( const QString &pServerId, const QString &pChannelName,
                                             const QStringList &pUsersNames, bool pReadonly = false );
        Q_INVOKABLE void addUsersToChannel( const QString &pServerId, const QString &pChannelName,
                                            const QString &pUsernames );
        Q_INVOKABLE void openFileExternally( const QString &pPath );
        Q_INVOKABLE bool hasCameraPermission();
        Q_INVOKABLE QString getCleanString( const QString &pText );
        Q_INVOKABLE void uploadSharedFileToChannel( const QString &channelId );
        Q_INVOKABLE void joinJitsiCall( const QString &pServer, const QString &pChannelId,
                                        const QString &pMessageId );

        Q_INVOKABLE QString getUsername( const QString &pServerId );
        Q_INVOKABLE void setCurrentChannel( const QString &pServerId, const QString &pCurrentChannel,
                                            const QString &pChannelName );
        Q_INVOKABLE void getNewVideoPath();
        Q_INVOKABLE void setSetting( const QString &pKey, const QString &pValue );
        Q_INVOKABLE void getSetting( const QString &pKey );
        Q_INVOKABLE void callGalleryPicker( const QString &pChannelId );
        Q_INVOKABLE void createAccount( const QString &serverId, const QString &email,
                                        const QString &username, const QString &password );

        Q_INVOKABLE void markChannelAsRead( const QString &pChannelId );
        Q_INVOKABLE void loadRecentHistory( const QString &pChannelId );
        Q_INVOKABLE void loadHistoryTill( const QString &pChannelId, qint64 pTs );

        Q_INVOKABLE bool isServerReady();
        Q_INVOKABLE bool isStorageReady();

        Q_INVOKABLE void setStatusBarColor( const QString &pColor );

        Q_INVOKABLE QVariantMap checkForChannelSwitchRequest();
        Q_INVOKABLE void resetChannelSwitchRequest();

        Q_INVOKABLE bool customEmojisReady();

        Q_INVOKABLE void checkLoggedIn();

        Q_INVOKABLE void getChannelDetails( const QString &pServerId, const QString &pChannelName );

        Q_INVOKABLE void createVideoCall( const QString &pServerId, const QString &pChannelId );

        Q_INVOKABLE void copyToClipboard( const QString &text );

        Q_INVOKABLE void blockUser( const QString &pChannelId );

        Q_INVOKABLE void unBlockUser( const QString &pChannelId );

        Q_INVOKABLE void leaveChannel( const QString &pChannelId );

        Q_INVOKABLE void hideChannel( const QString &pChannelId );

        Q_INVOKABLE void reportAbusiveContent( const QString &pMessageId, const QString &pAuthor );

        Q_INVOKABLE void searchMessage( const QString &pTerm, const QString &pChannelId );

        Q_INVOKABLE void searchRoom( const QString &pTerm );

        Q_INVOKABLE void searchRoomByType( const QString &pTerm, const QString &pType );

        Q_INVOKABLE void setUserDefaultStatus( int pStatus );

        Q_INVOKABLE void clearWebViewCookies();

        Q_INVOKABLE void deleteMessage(QString rid,QString id);
        Q_INVOKABLE void resetConnection(void);

         Q_INVOKABLE void registerServer( RocketChatServerData *pServer );

        void addLoginMethod( const QMap<QString, QVariant> &pMethod );

        void resetLoginMethods();

        void openIosFile( const QString &fileName );

        void registerForPush();
        void openUrl( const QString &url );

        void openFileNameReady( const QString &pFile );

        int getUserStatus();

        private:
        QMutex newServerMutex;

        //TODO: switch from shared pointer to normal ones, to avoid these hacks

        QThread mServerThread;
        QGuiApplication *mApp = nullptr;
        QString mCurrentChannel;
        QMap<QString, RocketChatServerData * > mServerMap;
        QNetworkConfigurationManager mNetworkConfiguration;
        QInputMethod *mInputMethod = nullptr;
        QHash<QString, uint> mUnreadSum;

        int mUserStatus = 2;



#ifdef Q_OS_ANDROID
        AndroidStatusBarColor *mAndroidStatusBarColor = nullptr;
        Notifications mNotificationsObject;
        AndroidFileDialog *mAndroidFileDialog = nullptr;
#endif

        QVariantMap mChannelSwitchRequest;

        int mLastBadgeCount = -1;

        bool mServerStatus = false;
        bool mStorageStatus = false;
        bool mInitialized = false;
        bool mDdpConnectionEstablished = false;
        bool mEmojisReady = false;

        QString mChannelToSwitchTo;
        QString mChannelToSwitchToType;

        QString currentChannel;
        void onDDPConnected( const QString &pServerId );
        void onOnlineStateChanged( bool pStat );
        void onApplicationStateChanged( const Qt::ApplicationState &pState );
        void onLogout( const QString &pServerId );
        void onUnreadCountChanged( const QString &pServerId, uint pUnread );
        void onLoggedIn( const QString &pServerId );
        void onChannelSwitchRequest( const QSharedPointer<RocketChatChannel> &pChannel );

        void serverReadySlot();
        void storageReadySlot();

#ifdef Q_OS_ANDROID
        void openAndroidFileDialog( QString channelId );
#endif
#if defined(Q_OS_ANDROID)||defined(Q_OS_IOS)
        void checkForpendingNotification();
#endif
        QString mFileToShare;
        void onClose( void );

        void onKeyboardVisiblityChanged();

        void onEmojisReady( const QVariantList &pEmojiList );

        void onChannelSortReceived( const QVariantMap &pSortOrder, const QString &channelType );

        void onAllChannelsReceived( const QVariantList &pChannels );

        void onServerSlotsReady();

        void onExternalChannelSwitchRequest( const QString &pName, const QString &pType );

    signals:

        void fileRessourceProcessed( QString url, QString path, bool showInline );
        void serverConnected( QString serverid );
        void loggedIn( QString serverid );
        void hashLoggedIn( QString server );
        void loggedOut( QString server );
        void loginError();
        void offline( void );
        void fileUploadFinished( QString fileId );
        void fileuploadStarted( QString data );
        void fileUploadProgressChanged( QString data );
        void error( QString text );
        void channelSwitchRequest( QString server, QString rid, QString name, QString type,
                                   bool readonlyFlag );
        void openShareDialog();
        void serverReady();
        void storageReady();
        void emojisReady( QVariantList emojis );
        //TODO: use QVariant...
        void channelDetailsReady( QVariantMap details, QString channelId );
        void noJitsiMeetAvailable();
        void offlineMode( void );
        void pushTokenReceived( QString pToken );
        void pushMessageReceived( QString pServer, QString pRid, QString pName, QString pType );
        void loggingIn();
        void userStatusChanged( int status );
        void videoPath( const QString &pPath );
        void setting( const QString &key, const QString &value );

        // iOS helper
        void setBadge( uint pNumber );
        void checkForLinkedFile();
        void openIOSFileDialog( QString pFile );
        void openGallery();
        void checkForpendingNotificationIOS();
        void registerForPushIOS();
        void clearAllCookies();
};

#endif // ROCKETCHAT_H