import { test, module } from 'qunit';
import withMomentTimezoneData, { reset } from 'web-client/utilities/with-moment-timezone-data';
import RSVP from 'rsvp';
import timezoneData from 'web-client/mirage/fixtures/timezones';
import tz from 'moment-timezone';

function resetTimezoneData() {
  // reset withMomentTimezoneData loading state
  reset();

  // Clear out moment.tz data to avoid test ordering issues. Testing strategy from moment.timezone:
  // https://github.com/moment/moment-timezone/blob/32ef9eff5781a7fa57f75a84caebedc905d2ab8a/tests/moment-timezone/names.js
  clearObject(tz._links);
  clearObject(tz._zones);
  clearObject(tz._names);
}

module('Unit | Utilities | with-moment-timezone-data', {
  beforeEach() {
    // we reset both before and after because some tests use withMomentTimezoneData
    // which can begin these tests in a loaded state.
    resetTimezoneData();
  },

  afterEach() {
    resetTimezoneData();
  }
});

test('loading once, then using the cached request later', function(assert) {
  assert.expect(5);

  let requestCount = 0;

  let request = () => {
    requestCount++;

    return RSVP.resolve(timezoneData);
  };

  assert.equal(tz.names().length, 0, 'starts with no timezones');

  return withMomentTimezoneData(request).then(loadedTz => {
    assert.equal(loadedTz.names().length, 7, 'loads the timezones');
    assert.equal(requestCount, 1, 'made one request');

    return withMomentTimezoneData(request);
  }).then(loadedTz => {
    assert.equal(loadedTz.names().length, 7, 'timezones still loaded');
    assert.equal(requestCount, 1, 'original request is cached');
  });
});

test('handling multiple calls before the first request resolves', function(assert) {
  assert.expect(1);

  let requestCount = 0;

  let request = () => {
    requestCount++;

    return RSVP.resolve(timezoneData);
  };

  return RSVP.all([
    withMomentTimezoneData(request),
    withMomentTimezoneData(request),
    withMomentTimezoneData(request)
  ]).then(() => {
    assert.equal(requestCount, 1, 'only makes one request');
  });
});

test('failing on first request, and allowing a retry', function(assert) {
  assert.expect(5);

  let requestCount = 0;

  let failRequest = () => {
    requestCount++;

    return RSVP.reject();
  };

  let successRequest = () => {
    requestCount++;

    return RSVP.resolve(timezoneData);
  };

  assert.equal(tz.names().length, 0, 'starts with no timezones');

  return withMomentTimezoneData(failRequest).catch(() => {
    assert.equal(tz.names().length, 0, 'still has no timezones');
    assert.equal(requestCount, 1, 'made one request');

    return withMomentTimezoneData(successRequest);
  }).then(() => {
    assert.equal(tz.names().length, 7, 'loads the timezones');
    assert.equal(requestCount, 2, 'made another request');
  });
});

function clearObject (obj) {
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      delete obj[key];
    }
  }
}
