/* globals _ */

import Mixin from 'ember-metal/mixin';
import Ember from 'ember';
import LoadingCollectionMixin from 'web-client/models/core/mixins/instance/loading-collection';

const { on } = Ember;

export default Mixin.create(LoadingCollectionMixin, {
  queryOffset: 0,
  prevLength: 0,

  /**
   * for backwards compatibility with callers of old data layer
   *
   * @returns {*}
   * @deprecated
   */
  loadMore: function () {
    return this.load();
  },

  /** Private helpers */

  /**
   * The Ember addObjects method only adds objects to the collection that are not already present in it.
   * There are 3 cases to consider:
   *
   * 1) a page load returns at least 1 new result, thus altering the length of the collection
   * 2) a page load returns at least 1 result, and all objects in the result are already present in the
   *    collection, thus causing no change in its length.
   * 3) a page load returns 0 results, indicating that the end of the collection has been reached and
   *    no further page loads are needed.
   *
   * !! Point #3 is NOT technically true -- it is just assumed since it is convenient.
   *    The underlying collection can change between loads, so a user may
   *    hit the end of a collection at time 0, but at time 1, more elements may have been
   *    added to the collection. this edge case is not currently handled. !!
   *
   * In general, this is not designed to guarantee every element in the collection is displayed as it
   * changes over time. As the page # advances, it simply attempts to get to the end of the collection
   * once, which should give an adequate UX in the vast majority of cases.
   */
  _incrementOffset: on('contentSet', function () {
    if (this.get('length') > this.get('prevLength')) {
      this.set('queryOffset', this.get('queryOffset') + (this.get('length') - this.get('prevLength')));
      this.set('prevLength', this.get('length'));
    } else {
      this.set('queryOffset', this.pageSize + this.get('queryOffset'));
    }
  }),

  _checkInterface: on('init', function () {
    this._super();

    if (typeof this.load !== 'function' || !this.pageSize) {
      throw new Error("Please implement the required interface.");
    }
  }),

  /**
   * @override
   * @returns {boolean}
   * @private
   */
  _shouldLoad: function () {
    return true;
  },

  /**
   *
   * @param rawContent
   * @private
   */
  _setContent: function (rawContent) {
    let model = this.get('model'),
      itemSerializer = this.get('itemSerializer'),
      content = this.get('serializer').deserialize(rawContent);

    // see comment on #_incrementOffset
    this.set('gotNonEmptyResults', content.items && content.items.length);
    this.set('total', content.total);

    let newModels = content.items.map(function (itemContent) {
      let item = itemSerializer.deserialize(itemContent);
      if (!_.has(item, 'id')) {
        throw new Error("Item must define its id field.") ;
      }

      let instance = model.find({id: item.id});
      instance._loadSuccess(itemContent);
      return instance;
    });

    this.addObjects(newModels);
    return content;
  }
});
