import EmberObject from 'ember-object';
import { moduleFor, test } from 'ember-qunit';
import RSVP from 'rsvp';
import { A as emberA } from 'ember-array/utils';

moduleFor('service:vod-chat-service', {
  beforeEach() {
    this.video = {
      id: 1,
      recorded_at: new Date()
    };
  }
});

test('tick passes requestObject through to requestChunk, pushCachedMessages when the service has a video', function (assert) {
  assert.expect(4);
  let fakeRequest = {loadedMessages: []};
  let service = this.subject({
    buildTickRequestObject() {
      return fakeRequest;
    },
    requestChunk: function (request) {
      assert.ok(true, "requestChunk was called");
      assert.equal(request, fakeRequest);
    },
    pushCachedMessages: function (request) {
      assert.ok(true, "pushCachedMessages was called");
      assert.equal(request, fakeRequest);
    }
  });

  service.setVideo(this.video);
  service.tick(10);
});

test('clearing the video prevents network requests', function (assert) {
  let requestCount = 0;

  let service = this.subject({
    requestChunk() {
      requestCount++;
    }
  });

  service.setVideo(this.video);
  service.clearVideo(this.video);

  service.tick(10);

  assert.equal(requestCount, 0, 'no requests were sent');
});

test('when lastLoadTime > absoluteTime requestChunk does nothing', function (assert) {
  assert.expect(1);

  let fakeRequest = {lastLoadTime: 100, absoluteTime: 0};
  let service = this.subject({
    store: {
      query: function () {
        assert.ok(false, "shouldn't have called store.query");
      }
    }
  });
  service.requestChunk(fakeRequest);
  assert.ok(true, "properly neglected to call store.query");

});

test('when lastLoadTime < absoluteTime requestChunk should request a chunk and process messages', function (assert) {
  assert.expect(4);
  let fakeRequest = {lastLoadTime: 0, absoluteTime: 1, loadedMessages: emberA([])};
  let fakeEmberDataArray = {
    toArray() {
      return emberA(["foobar"]);
    }
  };
  let service = this.subject({
    store: {
      query: function () {
        return RSVP.resolve().then(function () {
          assert.ok(true, "should call store.query");
          return fakeEmberDataArray;
        });
      }
    }
  });
  return service.requestChunk(fakeRequest).then(function () {
    assert.deepEqual(fakeRequest.loadedMessages, ["foobar"], "After requesting a chunk messages get pushed to loadedMessages");
    assert.notOk(service.get('timeTravelingForward'), "timeTravelingForward got reset to false");
    assert.notOk(service.get('timeTravelingBackward'), "timeTravelingBackward got reset to false");
  });
});

test('when lastLoadTime < absoluteTime and the request 404s we should flag notFound', function (assert) {
  assert.expect(3);
  let fakeRequest = {lastLoadTime: 0, absoluteTime: 1, loadedMessages: emberA([])};
  let fakeError = {errors: [{status: 404}]};
  let service = this.subject({
    store: {
      query: function () {
        return RSVP.reject(fakeError);
      }
    }
  });
  return service.requestChunk(fakeRequest).then(function () {
    assert.equal(service.get('notFound'), true, "notFound got set to true");
    assert.notOk(service.get('timeTravelingForward'), "timeTravelingForward got reset to false");
    assert.notOk(service.get('timeTravelingBackward'), "timeTravelingBackward got reset to false");
  });
});

test('buildTickRequestObject creates the previous 30 second bounded chunkRequestTime', function (assert) {
  let service = this.subject({
    video: {
      recordedAt: 1000
    }
  });
  let time = 31 * 1000;
  let requestObject = service.buildTickRequestObject(time);
  assert.equal(requestObject.chunkRequestTime, 31 * 1000, "We are at relative time 00:31, yet we request the chunk for relative time 00:30");
});

test('pushCachedMessages pushes a message in between the current time and the last tick time', function (assert) {
  assert.expect(1);

  let message = EmberObject.create({
      timestamp: 25
    });
  let request = {
    absoluteTime: 30,
    lastTickTime: 20,
    lastLoadTime: 60,
    loadedMessages: emberA([message])
  };
  let service = this.subject({
    pushMessage: function () {
      assert.ok(true, "pushed a message");
    }
  });
  service.pushCachedMessages(request);

});

test('pushCachedMessages does not push a message outside of current time and last tick time', function (assert) {
  assert.expect(1);

  let request = {
    absoluteTime: 30,
    lastTickTime: 20,
    lastLoadTime: 60,
    loadedMessages: emberA([
      EmberObject.create({
            timestamp: 19
          }),
      EmberObject.create({
            timestamp: 31
          })
      ])
  };
  let service = this.subject({
    pushMessage: function () {
      assert.ok(false, "pushed a message, but shouldn't have");
    }
  });
  service.pushCachedMessages(request);
  assert.ok(true, "didn't push any messages");

});

test('pushCachedMessages does not push a message outside of the buffer', function (assert) {
  assert.expect(1);

  let message = EmberObject.create({
      timestamp: 25
    });
  let request = {
    absoluteTime: 90 * 1000,
    lastTickTime: 20,
    lastLoadTime: 60,
    loadedMessages: emberA([message])
  };
  let service = this.subject({
    pushMessage: function () {
      assert.ok(false, "pushed a message, but shouldn't have");
    }
  });
  service.pushCachedMessages(request);
  assert.ok(true, "properly neglected to push a message");

});

test('on seek, removes all messages before horizontal line and horizontal line if it exists', function (assert) {
  let messages = emberA([
      EmberObject.create({
        message: "S A D B O Y S"
      }),
      EmberObject.create({
        isHorizontalLine: true
      })
    ]);
  let service = this.subject({
    messages
  });
  service.seek(0);
  assert.deepEqual(service.get("messages"), [], "messages has been properly cleared");
});

test('on seek, grays out old messages and adds a horizontal line', function (assert) {
  let messages = emberA([
        EmberObject.create({
          message: "Tatted on my chest"
        })
      ]);
  let service = this.subject({
    messages
  });
  service.seek(0);
  assert.equal(service.get('messages.firstObject.grayed'), true, "old message is grayed");
  assert.equal(service.get('messages.lastObject.isHorizontalLine'), true, "last message is a horizontal line");
});

test('on seek, sets time traveling forward if the direction was forward', function (assert) {
  let service = this.subject({
    timeDirectionForward: true
  });
  service.seek(0);
  assert.equal(service.get('timeTravelingForward'), true, "direction was forward, we are time traveling forward");
});

test('on seek, sets time traveling backward if the direction was backward', function (assert) {
  let service = this.subject({
    timeDirectionForward: false
  });
  service.seek(0);
  assert.equal(service.get('timeTravelingBackward'), true, "direction was backward, we are time traveling backward");
});

test('pushMessage sets a color if it is null', function (assert) {
  let msgObject = EmberObject.create({
    color: null,
    from: "RTZ"
  });
  let service = this.subject({messages: emberA([])});
  service.pushMessage(msgObject);
  assert.equal(service.get("messages.length"), 1, "pushed a message to messages");
  assert.notEqual(service.get("messages.lastObject.color"), null, "added message's color is not null");
});

test("pushMessage doesn't set a color if the message already has one", function (assert) {
  let color = "YUNG GREEN";
  let msgObject = EmberObject.create({
    from: "RTZ",
    color
  });
  let service = this.subject({messages: emberA([])});
  service.pushMessage(msgObject);
  assert.equal(service.get("messages.length"), 1, "pushed a message to messages");
  assert.equal(service.get("messages.lastObject.color"), color, "color that was set should still be set");
});

test("pushMessage adds a message to messages", function (assert) {
  let msgObject = EmberObject.create({
    from: "RTZ"
  });
  let service = this.subject({messages: emberA([])});
  service.pushMessage(msgObject);
  assert.equal(service.get("messages.length"), 1, "pushed a message to messages");
});

test("pushMessage observes the MESSAGE_BUFFER_SIZE", function (assert) {
  let bufferLength = 100;
  let emberObject = EmberObject.create({});
  let msgObject = EmberObject.create({
    from: "RTZ"
  });
  let msgArray = new Array(bufferLength).map(() => emberObject);
  let messages = emberA(
      Array(...msgArray)
    );
  let service = this.subject({messages});
  assert.equal(service.get('messages.length'), bufferLength, "buffer starts at buffer length");
  service.pushMessage(msgObject);
  assert.equal(service.get('messages.length'), bufferLength, "buffer stays at buffer length after pushing a message");
});
