var sparkle = sparkle || {};
(function () {

    // Check if SignalR is defined
    if (!signalR) {
        return;
    }

    // Create namespaces
    sparkle.signalr = sparkle.signalr || {};
    sparkle.signalr.hubs = sparkle.signalr.hubs || {};
    sparkle.signalr.reconnectTime = sparkle.signalr.reconnectTime || 5000;
    sparkle.signalr.maxTries = sparkle.signalr.maxTries || 8;
    sparkle.signalr.increaseReconnectTime = sparkle.signalr.increaseReconnectTime || function (time) {
        return time * 2;
    };

    // Configure the connection for sparkle.signalr.hubs.common
    function configureConnection(connection) {
        // Set the common hub
        sparkle.signalr.hubs.common = connection;

        let tries = 1;
        let reconnectTime = sparkle.signalr.reconnectTime;

        // Reconnect loop
        function tryReconnect() {
            if (tries <= sparkle.signalr.maxTries) {
                connection.start()
                    .then(function () {
                        reconnectTime = sparkle.signalr.reconnectTime;
                        tries = 1;
                        console.log('Reconnected to SignalR server!');
                        sparkle.event.trigger('sparkle.signalr.reconnected');
                    }).catch(function () {
                    tries += 1;
                    reconnectTime = sparkle.signalr.increaseReconnectTime(reconnectTime);
                    setTimeout(function () {
                            tryReconnect()
                        },
                        reconnectTime
                    );
                });
            }
        }

        // Reconnect if hub disconnects
        connection.onclose(function (e) {
            if (e) {
                sparkle.log.debug('Connection closed with error: ' + e);
            } else {
                sparkle.log.debug('Disconnected');
            }

            if (!sparkle.signalr.autoReconnect) {
                return;
            }
            
            sparkle.event.trigger('sparkle.signalr.disconnected');
            tryReconnect();
        });

        // Register to get notifications
        connection.on('getNotification', function (notification) {
            sparkle.event.trigger('sparkle.notifications.received', notification);
        });
    }

    // Connect to the server for sparkle.signalr.hubs.common
    function connect() {
        var url = sparkle.signalr.url || (sparkle.appPath + 'signalr');

        // Start the connection
        startConnection(url, configureConnection)
            .then(function (connection) {
                sparkle.log.debug('Connected to SignalR server!'); //TODO: Remove log
                sparkle.event.trigger('sparkle.signalr.connected');
                // Call the Register method on the hub
                connection.invoke('register').then(function () {
                    sparkle.log.debug('Registered to the SignalR server!'); //TODO: Remove log
                });
            })
            .catch(function (error) {
                sparkle.log.debug(error.message);
            });
    }

    // Starts a connection with transport fallback - if the connection cannot be started using
    // the webSockets transport the function will fallback to the serverSentEvents transport and
    // if this does not work it will try longPolling. If the connection cannot be started using
    // any of the available transports the function will return a rejected Promise.
    function startConnection(url, configureConnection) {
        if (sparkle.signalr.remoteServiceBaseUrl) {
            url = sparkle.signalr.remoteServiceBaseUrl + url;
        }

        // Add query string: https://github.com/aspnet/SignalR/issues/680
        if (sparkle.signalr.qs) {
            url += (url.indexOf('?') == -1 ? '?' : '&') + sparkle.signalr.qs;
        }

        return function start(transport) {
            sparkle.log.debug('Starting connection using ' + signalR.HttpTransportType[transport] + ' transport');
            var connection = new signalR.HubConnectionBuilder()
                .withUrl(url, transport)
                .build();

            if (configureConnection && typeof configureConnection === 'function') {
                configureConnection(connection);
            }

            return connection.start()
                .then(function () {
                    return connection;
                })
                .catch(function (error) {
                    sparkle.log.debug('Cannot start the connection using ' + signalR.HttpTransportType[transport] + ' transport. ' + error.message);
                    if (transport !== signalR.HttpTransportType.LongPolling) {
                        return start(transport + 1);
                    }

                    return Promise.reject(error);
                });
        }(signalR.HttpTransportType.WebSockets);
    }

    sparkle.signalr.autoConnect = sparkle.signalr.autoConnect === undefined ? true : sparkle.signalr.autoConnect;
    sparkle.signalr.autoReconnect = sparkle.signalr.autoReconnect === undefined ? true : sparkle.signalr.autoReconnect;
    sparkle.signalr.connect = sparkle.signalr.connect || connect;
    sparkle.signalr.startConnection = sparkle.signalr.startConnection || startConnection;

    if (sparkle.signalr.autoConnect && !sparkle.signalr.hubs.common) {
        sparkle.signalr.connect();
    }
})();