import { assign } from 'ember-platform';
import RSVP from 'rsvp';
import EmberObject from 'ember-object';
import Evented from 'ember-evented';
import { moduleFor, test } from 'ember-qunit';

const MOCK_LOGIN = "MockLogin";
const MOCK_NONCE = "abcdefg";

let MockPubsub = EmberObject.extend(Evented, {
  setupService() {
    return RSVP.resolve();
  }
});

class MockImApi {
  publishMessage(message, options) {
    this._messageCapture = message;
    this._optionsCapture = options;

    return new RSVP.resolve();
  }
}

class MockEmotes {
  tryParseEmotes() {
    return [];
  }
}

moduleFor('service:whispers-shim', {
   needs: ['service:whispers-pubsub', 'service:im-api', 'service:tmi'],
   beforeEach: function() {
     let service = this.subject({
       pubsub: new MockPubsub(),
       imApi: new MockImApi(),
       emotes: new MockEmotes()
     });

     service._twitchUserLogin = () => { return MOCK_LOGIN; };
     service._recordWhisperSentReflection = () => {};
     service._scheduleRecordLocalRenderMetric = () => {};
   }
});

test('publishMessage calls im-api', function(assert) {
  assert.expect(2);
  let done = assert.async();
  let service = this.subject();
  let mockMessage = "some message";
  let mockOptions = { toLogin: "somelogin", nonce: MOCK_NONCE };

  service.publishMessage(mockMessage, mockOptions).then(() => {
    let imApi = service.get("imApi");
    assert.equal(imApi._messageCapture, mockMessage);
    assert.deepEqual(imApi._optionsCapture, assign({}, mockOptions, {nonce: MOCK_NONCE }));
    done();
  });
});

test('publishMessage stores a nonce', function(assert) {
  let service = this.subject();

  service.publishMessage("some message", { toLogin: "somelogin", nonce: MOCK_NONCE });

  let expectedNonces = {};
  expectedNonces[MOCK_NONCE] = { receivedOnPubsub: false };

  assert.deepEqual(service.get("nonces"), expectedNonces);
});

test("triggerChatWhisper triggers a chat_whisper event", function(assert) {
  assert.expect(1);
  let done = assert.async();
  let service = this.subject();

  let expectedMessage = {
    body: "body",
    toLogin: "login",
    nonce: "nonce"
  };

  service.on("chat_whisper", (message) => {
    assert.strictEqual(message, expectedMessage);

    done();
  });

  service.triggerChatWhisper(expectedMessage);
});

test('it triggers a whisper event from pubsub', function(assert) {
  assert.expect(1);
  let done = assert.async();
  let service = this.subject();

  service.on("whisper", () => {
    assert.ok(true, "whisper triggered");
    done();
  });

  service.setupService().then(() => {
    let mockMessage = { nonce: MOCK_NONCE };
    service.get("pubsub").trigger("whisper", mockMessage);
  });
});

test('it does not triggers a whisper event if locally rendered', function(assert) {
  assert.expect(2);
  let done = assert.async();
  let service = this.subject();

  let mockMessage = {
    nonce: MOCK_NONCE
  };

  let whisperTriggered = false;

  service.on("whisper", () => {
    whisperTriggered = true;
  });

  service.get("nonces")[MOCK_NONCE] = { receivedOnPubsub: false };

  service.setupService().then(() => {
    service.get("pubsub").trigger("whisper", mockMessage);
  }).then(() => {
    assert.ok(!whisperTriggered, "whisper event should not have been triggered");
    assert.ok(service.get("nonces")[MOCK_NONCE].receivedOnPubsub, "nonce should have been marked as received");
    done();
  });
});


test('it triggers a thread event from pubsub', function(assert) {
  assert.expect(1);
  let done = assert.async();
  let service = this.subject();

  service.on("thread", () => {
    assert.ok(true, "thread triggered");
    done();
  });

  service.setupService().then(() => {
    service.get("pubsub").trigger("thread");
  });
});

test('it triggers a threads event from pubsub', function(assert) {
  assert.expect(1);
  let done = assert.async();
  let service = this.subject();

  service.on("threads", () => {
    assert.ok(true, "threads triggered");
    done();
  });

  service.setupService().then(() => {
    service.get("pubsub").trigger("threads");
  });
});

test('it triggers a reconnecting event from pubsub', function(assert) {
  assert.expect(1);
  let done = assert.async();
  let service = this.subject();

  service.on("reconnecting", () => {
    assert.ok(true, "reconnecting triggered");
    done();
  });

  service.setupService().then(() => {
    service.get("pubsub").trigger("reconnecting");
  });
});
