import { moduleFor } from 'ember-qunit';
import test from 'ember-sinon-qunit/test-support/test';
import sinon from 'sinon';
import RSVP from 'rsvp';

const simpleEmoteSet = [
  {
    id: 1,
    code: 'Kappa',
    isRegex: false
  },
  {
    id: 2,
    code: new RegExp('\:-?(p|P)'),
    isRegex: true
  },
  {
    id: 3,
    code: 'Keepo',
    isRegex: false
  },
  {
    id: 4,
    code: new RegExp('\:-?(/|\)'),
    isRegex: true
  }
];

moduleFor('service:user-emotes', 'Unit | Service | user emotes', {
  needs: ['service:api', 'service:session']
});

test('`populate` returns a resolved promise when logged out', function(assert) {
  assert.expect(2);

  let service = this.subject();

  service._isLoggedIn = function() { return false; };

  let promise = service.populate();

  promise.then(response => {
    assert.deepEqual(response, {});
  });

  let nextPromise = service.populate();
  assert.strictEqual(nextPromise, promise);
});

test('`populate` returns the twitch API response when logged in', function(assert) {
  assert.expect(2);

  // TODO instead of this custom stubbing,
  // use mirage and stubLogin to simulate signed-in user

  let testLogin = "test-user";
  let getCurrentUser = function() { return RSVP.resolve({login: testLogin}); };

  let ajaxStub = this.stub();
  ajaxStub.withArgs('get', `users/${testLogin}/emotes`)
    .returns(RSVP.resolve({"emoticon_sets": {} }));

  let service = this.subject({
    api: { request: ajaxStub },
    session: { getCurrentUser },
    _isLoggedIn: function() { return true; }
  });

  let promise = service.populate();

  promise.then(response => {
    assert.deepEqual(response, {"emoticon_sets": {}});
  });

  let nextPromise = service.populate();
  assert.strictEqual(nextPromise, promise);
});


// have to use raw sinon because this test is async. ember-sinon-qunit resets
// stubs after the event loop
test('`parseEmotes` uses emotes from the result of populate()', function(assert) {
  let done = assert.async();
  assert.expect(3);
  let service = this.subject();
  let postBody = 'Keepo';
  let emotes = {"emoticon_sets": simpleEmoteSet};

  let populateStub = sinon.stub(service, 'populate');
  populateStub.onFirstCall().returns(RSVP.resolve(emotes));

  let buildStub = sinon.stub(service, '_buildAndParseEmotes');

  service.parseEmotes(postBody).then(() => {
    assert.ok(populateStub.calledOnce);
    assert.ok(buildStub.calledOnce);
    assert.ok(buildStub.calledWithExactly(postBody, emotes));
    done();
  });
});

test('`tryParseEmotes` uses emotes from its emotes property', function(assert) {
  let service = this.subject();
  let postBody = 'Keepo';
  let buildStub = this.stub(service, '_buildAndParseEmotes');
  let emotes = {"emoticon_sets": simpleEmoteSet};
  service.set('_emotes', emotes);

  service.tryParseEmotes(postBody);

  assert.ok(buildStub.calledOnce);
  assert.ok(buildStub.calledWithExactly(postBody, emotes));
});

test('it parses an emote by itself', function(assert) {
  let service = this.subject();
  let postBody = 'Keepo';

  let results = service._parseEmotes(postBody, simpleEmoteSet);
  assert.equal(results.length, 1, 'Correct number of emotes detected');

  let keepoResult = results[0];
  assert.equal(keepoResult.id, 3, 'Correct ID detected');
  assert.equal(keepoResult.start, 0, 'Emote start location detected');
  assert.equal(keepoResult.end, 4, 'Emote end location detected');
});

test('it returns the empty set when to emotes are provided', function(assert) {
  let service = this.subject();

  let postBody = 'Keepo';

  let results = service._parseEmotes(postBody, {});
  assert.equal(results.length, 0, 'Correct number of emotes detected');
});

test('it parses an emote by surrounded by text', function(assert) {
  let service = this.subject();

  let postBody = 'I want to send you this emote Keepo there it was.';

  let results = service._parseEmotes(postBody, simpleEmoteSet);
  assert.equal(results.length, 1, 'Correct number of emotes detected');

  let keepoResult = results[0];
  assert.equal(keepoResult.id, 3, 'Correct ID detected');
  assert.equal(keepoResult.start, 30, 'Emote start location detected');
  assert.equal(keepoResult.end, 34, 'Emote end location detected');
});

test('it parses a regular expression emote by itself', function(assert) {
  let service = this.subject();

  let postBody = ':-P';

  let results = service._parseEmotes(postBody, simpleEmoteSet);
  assert.equal(results.length, 1, 'Correct number of emotes detected');

  let toungeResult = results[0];
  assert.equal(toungeResult.id, 2, 'Correct ID detected');
  assert.equal(toungeResult.start, 0, 'Emote start location detected');
  assert.equal(toungeResult.end, 2, 'Emote end location detected');
});

test('it detects no emotes on plain text', function(assert) {
  let service = this.subject();

  let postBody = 'This is a pretty great post with no emote content.  Twitch 2.0.';

  let results = service._parseEmotes(postBody, simpleEmoteSet);
  assert.equal(results.length, 0, 'Correct number of emotes detected');
});

test('it parses multiple different emotes', function(assert) {
  let service = this.subject();

  let postBody = 'Kappa Keepo :-P';

  let results = service._parseEmotes(postBody, simpleEmoteSet);
  assert.equal(results.length, 3, 'Correct number of emotes detected');

  let keepaResult = results[0];
  assert.equal(keepaResult.id, 1, 'Correct ID detected');
  assert.equal(keepaResult.start, 0, 'Emote start location detected');
  assert.equal(keepaResult.end, 4, 'Emote end location detected');

  let keepoResult = results[1];
  assert.equal(keepoResult.id, 3, 'Correct ID detected');
  assert.equal(keepoResult.start, 6, 'Emote start location detected');
  assert.equal(keepoResult.end, 10, 'Emote end location detected');

  let toungeResult = results[2];
  assert.equal(toungeResult.id, 2, 'Correct ID detected');
  assert.equal(toungeResult.start, 12, 'Emote start location detected');
  assert.equal(toungeResult.end, 14, 'Emote end location detected');
});

test('it does not match subToken emotes', function(assert) {
  let service = this.subject();

  let postBody = "KappaJohn aKappab https://www.twitch.tv";
  let results = service._parseEmotes(postBody, simpleEmoteSet);

  assert.equal(results.length, 0, 'Correct number of emotes detected');
});

test('it parses multiple of the same emotes', function(assert) {
  let service = this.subject();

  let postBody = 'Kappa Kappa notKappa Kappa';

  let results = service._parseEmotes(postBody, simpleEmoteSet);
  assert.equal(results.length, 3, 'Correct number of emotes detected');

  let kappaOne = results[0];
  assert.equal(kappaOne.id, 1, 'Correct ID detected');
  assert.equal(kappaOne.start, 0, 'Emote start location detected');
  assert.equal(kappaOne.end, 4, 'Emote end location detected');

  let kappaTwo = results[1];
  assert.equal(kappaTwo.id, 1, 'Correct ID detected');
  assert.equal(kappaTwo.start, 6, 'Emote start location detected');
  assert.equal(kappaTwo.end, 10, 'Emote end location detected');

  let kappaThree = results[2];
  assert.equal(kappaThree.id, 1, 'Correct ID detected');
  assert.equal(kappaThree.start, 21, 'Emote start location detected');
  assert.equal(kappaThree.end, 25, 'Emote end location detected');
});
