/* globals _ */
import sinonTest from 'ember-sinon-qunit/test-support/test';
import sinon from 'sinon';
import { FakeExperimentService } from 'web-client/tests/helpers/experiment-group-test';
import moduleForIntegration from 'web-client/tests/helpers/module-for-integration';
import $ from 'jquery';

let service, fakeXhr, fakeTimer, requests;
const START_TIME = 1234567890;

moduleForIntegration('service:cdn-metrics', 'Integration | Service | CDN Metrics', {
  beforeEach() {
    // NOTE: have to restore() these in the body of each test.
    fakeXhr = sinon.useFakeXMLHttpRequest();
    requests = [];
    fakeTimer = sinon.useFakeTimers(START_TIME);

    fakeXhr.onCreate = function (xhr) {
      requests.push(xhr);
    };

    this.owner.register('service:experiments', FakeExperimentService);
    this.owner.lookup('service:experiments').use({ NEXUS_ROLLOUT: 'enabled' });
    service = this.subject();
    $.migrateReset();
  }
});

sinonTest('cdnExperiment selects assets and fetches each one', function (assert) {
  let timeElapsed = 123;
  // Don't actually send graphite metrics through the client-event-reporter.
  let mockStats = this.mock(service.stats);

  // Since we want to leave `service` mostly functional, let's stub out a few
  // choice functions instead of mocking the whole thing.
  this.stub(service, 'runTask')
    .onFirstCall().callsArgOn(0, service)
    .onSecondCall().returns();
  this.stub(service, '_chooseAssets').returns([
    {'group': 'test', 'name': 'success', 'url': 'https://success'},
    {'group': 'test', 'name': 'client-error', 'url': 'https://client-error'},
    {'group': 'test', 'name': 'server-error', 'url': 'https://server-error'}
  ]);

  mockStats.expects('logCounter').withExactArgs('test.success.success', 1).once();
  mockStats.expects('logTimer').withExactArgs('test.success.latency', timeElapsed).once();
  mockStats.expects('logCounter').withExactArgs('test.client-error.failure.4xx', 1).once();
  mockStats.expects('logCounter').withExactArgs('test.server-error.failure.5xx', 1).once();

  service.monitor();

  // Advance the clock by a set amount of time so we know all the exact timings sent to graphite and spade.
  fakeTimer.tick(timeElapsed);
  assert.equal(requests.length, 3);

  requests[0].respond(200, '<html>');
  // Trying to JSON deserialize non-json creates warnings here, but we don't want to deserialize
  // the responses for these downloads. ember-ajax always tries to json deserialize errors, so
  // let's check this before we respond with any errors.
  assert.strictEqual($.migrateWarnings.length, 0);

  requests[1].respond(400);
  requests[2].respond(500);

  let baseData = {
    group: 'test',
    latency: timeElapsed
  };

  assert.trackEvent('web_cdn_latency', _.extend({success: true, statusCode: 200, assetName: 'success'}, baseData));
  assert.trackEvent('web_cdn_latency', _.extend({success: false, statusCode: 400, assetName: 'client-error'}, baseData));
  assert.trackEvent('web_cdn_latency', _.extend({success: false, statusCode: 500, assetName: 'server-error'}, baseData));

  // Have to do these here or we won't ever make it to the afterEach callback.
  fakeXhr.restore();
  fakeTimer.restore();
});

sinonTest('cdnExperiment uses its own cache busting GET parameters', function (assert) {
  // Don't actually send graphite metrics through the client-event-reporter.
  this.stub(service.stats, 'logCounter');
  this.stub(service.stats, 'logTimer');

  // Since we want to leave `service` mostly functional, let's stub out a few
  // choice functions instead of mocking the whole thing.
  this.stub(service, 'runTask')
    .onFirstCall().callsArgOn(0, service)
    .onSecondCall().returns();
  this.stub(service, '_chooseAssets').returns([
    {'group': 'test', 'name': 'success', 'url': 'https://success'}
  ]);

  // Set POLL_INTERVAL to 5s and set up the assets/SAMPLE_SIZE so we loop after two samples,
  // hence the cache should be good for 10000ms.
  // The starting time is 1234567890 and we want to ignore the last 4 digits --> 123456.
  service.set('assets', [0, 1, 2, 3, 4]);
  service.set('SAMPLE_SIZE', 2);
  service.set('POLL_INTERVAL', 5 * 1000);
  let expectedCacheKey = 123456;

  service.monitor();
  fakeTimer.tick(1);

  assert.equal(requests.length, 1);
  assert.notEqual(requests[0].url.indexOf(`_cache=${expectedCacheKey}`), -1);
  requests[0].respond(200, '<html>');
  assert.strictEqual($.migrateWarnings.length, 0);

  // Have to do these here or we won't ever make it to the afterEach callback.
  fakeXhr.restore();
  fakeTimer.restore();
});
