import run from 'ember-runloop';
import Service from 'ember-service';
import RSVP from 'rsvp';
import { test, moduleForModel } from 'ember-qunit';
import {
  setup as setupMirage, teardown as teardownMirage
} from 'web-client/tests/helpers/setup-mirage-for-integration';


const SESSION_STUB = Service.extend({
  userData: {
    login: 'Extalix',
    id: 'extalix'
  }
});

const TMI_STUB = Service.extend({
  isIgnored() {
    return RSVP.resolve(false);
  }
});

const DEFAULT_THREAD_DATA = [
  { id: '1_2',
    participants: [
      { id: 1,
        display_name: 'Extalix',
        username: 'extalix',
        user_type: ['staff'],
        color: 'red',
        turbo: true
      },
      { id: 2,
        display_name: 'Bob',
        username: 'bob',
        user_type: [],
        color: 'green',
        turbo: false
      }
    ],
    last_read: 1,
    last_updated: new Date(),
    last_message: {
      id: 1,
      message: 'This is a first message',
      sent: new Date(),
      from: 1,
      tags: {}
    },
    spam_info: {
      last_marked_not_spam: 0,
      likelihood: 'low'
    }
  }
];

function setupGetThreads(server, threadData, total) {
  threadData = threadData || DEFAULT_THREAD_DATA;
  total = total || 1;

  server.get('/threads', function () {
    let response = {
      data: threadData,
      total: total,
      links: {
        self: '/threads'
      }
    };

    return response;
  });
}

moduleForModel('thread', 'serializer:thread', {
  needs: ['serializer:thread', 'model:participant', 'serializer:participant'],
  beforeEach() {
    setupMirage(this);
    this.register('service:session', SESSION_STUB);
    this.register('service:tmi', TMI_STUB);
    this.inject.service('session');
    this.inject.service('tmi');
  },
  afterEach() {
    teardownMirage(this);
  }
});

test('serialize drops old values and only returns updated value', function (assert) {
  let record = this.subject({'isMuted': false});
  run(() => {
    record.set('isMuted', true);
  });
  let serializedRecord = record.serialize();
  assert.deepEqual(serializedRecord, {muted: true}, 'serialized muted value correctly');
});

test('GET /threads with no threads returned', function (assert) {
  assert.expect(1);

  setupGetThreads(this.server, [], 0);
  return this.store().findAll('thread').then(threads => {
    assert.equal(threads.get('length'), 0, 'no threads loaded in the store');
  });
});

test('GET /threads with one thread returned serializes thread correctly', function (assert) {
  assert.expect(2);

  setupGetThreads(this.server);
  return this.store().findAll('thread').then(threads => {
    assert.equal(threads.get('length'), 1, 'one thread loaded in the store');

    let thread = this.store().peekRecord('thread', '1_2');
    assert.ok(thread, 'thread 1_2 exists in the store');
  });
});

test('GET /threads with one thread returned serializes participants correctly', function (assert) {
  assert.expect(8);

  setupGetThreads(this.server);

  return this.store().findAll('thread').then(() => {
    let thread = this.store().peekRecord('thread', '1_2'),
        participant1 = thread.get('participants').objectAt(0),
        participant2 = thread.get('participants').objectAt(1);
    assert.equal(participant1.get('id'), 1, 'first participant has id 1');
    assert.equal(participant2.get('id'), 2, 'second participant has id 2');
    assert.equal(participant1.get('displayName'), 'Extalix', 'first participant has display name Extalix');
    assert.equal(participant2.get('displayName'), 'Bob', 'second participant has display name Bob');
    assert.equal(participant1.get('username'), 'extalix', 'first participant has username extalix');
    assert.equal(participant2.get('username'), 'bob', 'second participant has username bob');
    assert.equal(participant1.get('color'), 'red', 'first participant has color red');
    assert.equal(participant2.get('color'), 'green', 'second participant has color green');
  });
});

test('normalizeQueryResponse serializes properly', function (assert) {
  assert.expect(4);
  this.server.get('/threads', (schema, request) => {
    assert.equal(request.queryParams.limit, 10, 'request has query param of limit = 10');
    assert.equal(request.queryParams.offset, 0, 'request has query param of offset = 0');
    let response = {
      data: DEFAULT_THREAD_DATA,
      total: 1,
      links: {
        self: '/threads'
      }
    };

    return response;
  });

  return this.store().query('thread', {offset: 0, limit: 10}).then(threads => {
    assert.equal(threads.get('length'), 1, 'response from query has only one thread');
    assert.equal(threads.objectAt(0).get('id'), '1_2', 'response from query has thread with id 1_2');
  });
});

test('normalizeSingleResponse serializes properly', function (assert) {
  assert.expect(1);

  this.server.get('/threads/1_2', () => {
    let response = DEFAULT_THREAD_DATA[0];
    response.links = {
      self: '/threads/1_2'
    };
    return response;
  });
  return run(() => this.store().findRecord('thread', '1_2').then(threadData => {
    assert.equal(threadData.get('id'), '1_2', 'thread returned from single record find is actually thread with id 1_2');
  }));
});

test('createDummyThreadForUser creates a dummy thread object that can be pushed into the store', function (assert) {
  assert.expect(12);

  let threadId = '1_2',
      currentUserData = {
        id: 1,
        name: 'Extalix',
        login: 'extalix'
      },
      otherUserData = {
        id: 2,
        name: 'Bob',
        login: 'bob'
      };

  let serializer = this.store().serializerFor('thread'),
      dummyThreadObj = serializer.createDummyThreadForUser(threadId, currentUserData, otherUserData);

  run(() => {
    let dummyThread = this.store().push(dummyThreadObj);
    assert.equal(dummyThread.get('id'), '1_2', 'dummythread has correct id when pushed');
    assert.equal(dummyThread.get('messages.length'), 0, 'dummy thread has no messages when pushed');
    assert.equal(dummyThread.get('isLocal'), true, 'dummy thread is marked as local when pushed');
    assert.equal(dummyThread.get('isMuted'), false, 'dummy thread is marked as not muted when pushed');
    assert.equal(dummyThread.get('lastUpdatedAt'), dummyThreadObj.data.attributes.lastUpdatedAt);
    assert.equal(dummyThread.get('lastReadId'), 0, 'dummy thread has last read id set to zero');

    let participant1 = dummyThread.get('participants').objectAt(0),
        participant2 = dummyThread.get('participants').objectAt(1);

    assert.equal(participant1.get('id'), 1, 'dummy thread has correct participant1 id');
    assert.equal(participant1.get('displayName'), 'Extalix', 'dummy thread has correct participant1 display name');
    assert.equal(participant1.get('username'), 'extalix', 'dummy thread has correct participant1 username');
    assert.equal(participant2.get('id'), 2, 'dummy thread has correct participant2 id');
    assert.equal(participant2.get('displayName'), 'Bob', 'dummy thread has correct participant2 display name');
    assert.equal(participant2.get('username'), 'bob', 'dummy thread has correct participant2 username');
  });
});
