/*global $, Whisper, Backbone, textsecure, extension*/

// This script should only be included in background.html
(function() {
  'use strict';

  window.Whisper = window.Whisper || {};

  var conversations = new Whisper.ConversationCollection();
  var inboxCollection = new (Backbone.Collection.extend({
    initialize: function() {
      this.on('change:timestamp change:name change:number', this.sort);

      this.listenTo(conversations, 'add change:active_at', this.addActive);
      this.listenTo(conversations, 'reset', function() {
        this.reset([]);
      });

      this.on(
        'add remove change:unreadCount',
        _.debounce(this.updateUnreadCount.bind(this), 1000)
      );
      this.startPruning();

      this.collator = new Intl.Collator();
    },
    comparator: function(m1, m2) {
      var timestamp1 = m1.get('timestamp');
      var timestamp2 = m2.get('timestamp');
      if (timestamp1 && !timestamp2) {
        return -1;
      }
      if (timestamp2 && !timestamp1) {
        return 1;
      }
      if (timestamp1 && timestamp2 && timestamp1 !== timestamp2) {
        return timestamp2 - timestamp1;
      }

      var title1 = m1.getTitle().toLowerCase();
      var title2 = m2.getTitle().toLowerCase();
      return this.collator.compare(title1, title2);
    },
    addActive: function(model) {
      if (model.get('active_at')) {
        this.add(model);
      } else {
        this.remove(model);
      }
    },
    updateUnreadCount: function() {
      var newUnreadCount = _.reduce(
        this.map(function(m) {
          return m.get('unreadCount');
        }),
        function(item, memo) {
          return item + memo;
        },
        0
      );
      storage.put('unreadCount', newUnreadCount);

      if (newUnreadCount > 0) {
        window.setBadgeCount(newUnreadCount);
        window.document.title =
          window.config.title + ' (' + newUnreadCount + ')';
      } else {
        window.setBadgeCount(0);
        window.document.title = window.config.title;
      }
      window.updateTrayIcon(newUnreadCount);
    },
    startPruning: function() {
      var halfHour = 30 * 60 * 1000;
      this.interval = setInterval(
        function() {
          this.forEach(function(conversation) {
            conversation.trigger('prune');
          });
        }.bind(this),
        halfHour
      );
    },
  }))();

  window.getInboxCollection = function() {
    return inboxCollection;
  };

  window.ConversationController = {
    get: function(id) {
      if (!this._initialFetchComplete) {
        throw new Error(
          'ConversationController.get() needs complete initial fetch'
        );
      }

      return conversations.get(id);
    },
    // Needed for some model setup which happens during the initial fetch() call below
    getUnsafe: function(id) {
      return conversations.get(id);
    },
    dangerouslyCreateAndAdd: function(attributes) {
      return conversations.add(attributes);
    },
    getOrCreate: function(id, type) {
      if (typeof id !== 'string') {
        throw new TypeError("'id' must be a string");
      }

      if (type !== 'private' && type !== 'group') {
        throw new TypeError(
          `'type' must be 'private' or 'group'; got: '${type}'`
        );
      }

      if (!this._initialFetchComplete) {
        throw new Error(
          'ConversationController.get() needs complete initial fetch'
        );
      }

      var conversation = conversations.get(id);
      if (conversation) {
        return conversation;
      }

      conversation = conversations.add({
        id: id,
        type: type,
      });
      conversation.initialPromise = new Promise(function(resolve, reject) {
        if (!conversation.isValid()) {
          var validationError = conversation.validationError || {};
          console.log(
            'Contact is not valid. Not saving, but adding to collection:',
            conversation.idForLogging(),
            validationError.stack
          );

          return resolve(conversation);
        }

        var deferred = conversation.save();
        if (!deferred) {
          console.log('Conversation save failed! ', id, type);
          return reject(new Error('getOrCreate: Conversation save failed'));
        }

        deferred.then(function() {
          resolve(conversation);
        }, reject);
      });

      return conversation;
    },
    getOrCreateAndWait: function(id, type) {
      return this._initialPromise.then(
        function() {
          var conversation = this.getOrCreate(id, type);

          if (conversation) {
            return conversation.initialPromise.then(function() {
              return conversation;
            });
          }

          return Promise.reject(
            new Error('getOrCreateAndWait: did not get conversation')
          );
        }.bind(this)
      );
    },
    getAllGroupsInvolvingId: function(id) {
      var groups = new Whisper.GroupCollection();
      return groups.fetchGroups(id).then(function() {
        return groups.map(function(group) {
          return conversations.add(group);
        });
      });
    },
    loadPromise: function() {
      return this._initialPromise;
    },
    reset: function() {
      this._initialPromise = Promise.resolve();
      conversations.reset([]);
    },
    load: function() {
      console.log('ConversationController: starting initial fetch');

      this._initialPromise = new Promise(
        function(resolve, reject) {
          conversations.fetch().then(
            function() {
              console.log('ConversationController: done with initial fetch');
              this._initialFetchComplete = true;
              resolve();
            }.bind(this),
            function(error) {
              console.log(
                'ConversationController: initial fetch failed',
                error && error.stack ? error.stack : error
              );
              reject(error);
            }
          );
        }.bind(this)
      );

      return this._initialPromise;
    },
  };
})();
