import moduleForComponent from 'web-client/tests/helpers/module-for-component';
import { test } from 'ember-qunit';
import hbs from 'htmlbars-inline-precompile';
import Service from 'ember-service';
import RSVP from 'rsvp';
import wait from 'ember-test-helpers/wait';
import { AuthenticatedSession } from 'web-client/tests/helpers/mock-session-service';

const CHANNEL_LOGIN = 'twitch';
const CHANNEL_ID = 1;

moduleForComponent('dashboards/live/stream-health', 'Integration | Component | dashboards/live/stream-health', {
  beforeEach() {
    this.register('service:session', AuthenticatedSession);
  }
});

test('renders stream health for non-channel owner', function(assert) {
  assert.expect(3);

  let done = assert.async();
  let modelPromise = { id: 'not_twitch', _id: 9000 };

  this.set('model', modelPromise);
  this.set('qualityCode', 101);
  this.set('reasonCodes', 1000);

  this.render(hbs`
    {{dashboards/live/stream-health
      channel=model
      isLive=true
      isChannelOwner=false
      qualityCode=qualityCode
      reasonCodes=reasonCodes
    }}
  `);

  return wait().then(() => {
    assert.elementCount(this.$('[data-test-selector="bitrate"]'), 0, 'bitrate info is not rendered');

    assert.elementCount(
      this.$('[data-test-selector="bitrate-unavailable"]'),
      1,
      'non-channel owner bitrate info is rendered'
    );

    assert.elementCount(this.$('[data-test-selector="health-label"]'), 1, 'stream health info is rendered');

    done();
  });
});

test('renders stream health for channel owner', function(assert) {
  assert.expect(5);

  let done = assert.async();
  let modelPromise = { id: CHANNEL_LOGIN, _id: CHANNEL_ID };
  let ingestServiceStub = Service.extend({
    getBitrate() {
      assert.ok(true, 'ingest service is invoked to GET bitrate');

      return RSVP.resolve({});
    }
  });

  this.owner.register('service:ingest', ingestServiceStub);
  this.set('model', modelPromise);
  this.set('qualityCode', 101);
  this.set('reasonCodes', [1000]);

  this.render(hbs`
    {{dashboards/live/stream-health
      channel=model
      isLive=true
      isChannelOwner=true
      qualityCode=qualityCode
      reasonCodes=reasonCodes
    }}
  `);

  return wait().then(() => {
    assert.elementCount(this.$('[data-test-selector="bitrate"]'), 1, 'bitrate info is rendered');

    assert.elementCount(
      this.$('[data-test-selector="bitrate-unavailable"]'),
      0,
      'non-channel owner bitrate info is not rendered'
    );

    assert.elementCount(this.$('[data-test-selector="health-label"]'), 1, 'stream health info is rendered');

    assert.elementCount(
      this.$('[data-test-selector="health-label"] [href="https://inspector.twitch.tv"]'),
      1,
      'anchor tag linking to the Twitch Inspector is rendered'
    );

    done();
  });
});

test('renders stream health for offline channel owner', function(assert) {
  assert.expect(8);

  let done = assert.async();
  let modelPromise = { id: CHANNEL_LOGIN, _id: CHANNEL_ID };
  let ingestServiceStub = Service.extend({
    getBitrate() {
      return RSVP.resolve({
        Channel: CHANNEL_LOGIN,
        Metric: 'bitrate',
        Results: []
      });
    }
  });

  this.owner.register('service:ingest', ingestServiceStub);

  this.set('model', modelPromise);
  this.set('testTrackDashboardEvent', () => {
    assert.ok(true, 'trackDashboardEvent function called');
  });

  this.render(hbs`
    {{dashboards/live/stream-health
      channel=model
      isLive=false
      isChannelOwner=true
      trackDashboardEvent=testTrackDashboardEvent
    }}
    <div id="wormhole-overlays"></div>
  `);

  return wait().then(() => {
    assert.stringIncludes(
      this.$('[data-test-selector="bitrate"]').text(),
      'You are currently not online. Start streaming live or run a stream test to see live data.',
      'offline description is rendered'
    );

    assert.elementCount(this.$('[data-test-selector="latest-bitrate"]'), 0, 'bitrate is not rendered');
    assert.elementCount(
      this.$('[data-test-selector="bitrate"] canvas'),
      0,
      'bitrate chart is not rendered'
    );

    assert.stringIncludes(
      this.$('[data-test-selector="health-label"] .pill').text(),
      'Offline',
      'stream health displays "Offline"'
    );

    this.$('[data-test-selector="stream-test-button"]').click();

    return wait();
  }).then(() => {
    assert.elementCount(this.$('[data-test-selector="stream-test-modal"]'), 1, 'modal is rendered');

    assert.stringIncludes(
      this.$('[data-test-selector="stream-test-modal"]').text(),
      'Run a Stream Test',
      'modal text is proper'
    );

    this.$('[data-test-selector="stream-test-modal"] button').click();

    return wait();
  }).then(() => {
    assert.elementCount(this.$('[data-test-selector="stream-test-modal"]'), 0, 'modal is no longer rendered');

    done();
  });
});

test('renders stream health for live channel owner', function(assert) {
  assert.expect(17);

  let done = assert.async();
  let modelPromise = { id: CHANNEL_LOGIN, _id: CHANNEL_ID };
  let health = {
    health_code: 101,
    health_reason_codes: [1000]
  };

  let ingestServiceStub = Service.extend({
    getBitrate() {
      return RSVP.resolve({
        Channel: CHANNEL_LOGIN,
        Metric: 'bitrate',
        Results: [
          {
            SessionID: '8ce432b2-6066-4247-843a-7fcd99f70bd3',
            Timestamp: 1476422751,
            Value: 1000.1234
          },
          {
            SessionID: '8ce432b2-6066-4247-843a-7fcd99f70bd3',
            Timestamp: 1476422756,
            Value: 2442.8125
          }
        ]
      });
    },

    getHealth() {
      return RSVP.resolve(health);
    }
  });

  this.owner.register('service:ingest', ingestServiceStub);

  this.set('model', modelPromise);
  this.set('qualityCode', 101);
  this.set('reasonCodes', [1000]);

  this.render(hbs`
    {{dashboards/live/stream-health
      channel=model
      isLive=true
      isChannelOwner=true
      qualityCode=qualityCode
      reasonCodes=reasonCodes
    }}
  `);

  return wait().then(() => {
    assert.elementCount(this.$('[data-test-selector="stream-test-button"]'), 0, 'stream test button is NOT rendered');

    assert.elementCount(
      this.$('[data-test-selector="bitrate"] canvas'),
      1,
      'bitrate chart is rendered'
    );

    assert.stringIncludes(
      this.$('[data-test-selector="latest-bitrate"]').text(),
      '2,443kb/s',
      'bitrate is correct'
    );

    assert.ok(
      this.$('[data-test-selector="health-label"] .pill').hasClass('pill--green'),
      'green pill is rendered'
    );

    assert.stringIncludes(
      this.$('[data-test-selector="health-label"]').text(),
      'Excellent',
      'stream health displays "Excellent"'
    );

    assert.stringIncludes(
      this.$('[data-test-selector="health-reason"]').text(),
      'No recommended changes!',
      'health reason code 1000 translates to "No recommended changes!"'
    );

    this.set('qualityCode', 102);
    this.set('reasonCodes', [1003, 1004, 1005, 1007]);

    return wait();
  }).then(() => {
    assert.ok(
      this.$('[data-test-selector="health-label"] .pill').hasClass('pill--orange'),
      'orange pill is rendered'
    );

    assert.stringIncludes(
      this.$('[data-test-selector="health-label"]').text(),
      'Warning',
      'stream health displays "Warning"'
    );

    assert.stringIncludes(
      this.$('[data-test-selector="health-reason"]').eq(0).text(),
      'Deprecated MP3 audio codec detected',
      'health reason code 1003 translates to MP3 deprecation'
    );

    assert.stringIncludes(
      this.$('[data-test-selector="health-reason"]').eq(1).text(),
      'Average stream bitrate too high',
      'health reason code 1004 translates to high bitrate'
    );

    assert.stringIncludes(
      this.$('[data-test-selector="health-reason"]').eq(2).text(),
      'Substantial frame drops detected',
      'health reason code 1005 translates to frame drop'
    );
    assert.stringIncludes(
      this.$('[data-test-selector="health-reason"]').eq(3).text(),
      'Keyframe interval too high',
      'health reason code 1007 translates to high keyframe interval'
    );

    this.set('qualityCode', 103);
    this.set('reasonCodes', [1001, 1002, 1006]);

    return wait();
  }).then(() => {
    assert.ok(
      this.$('[data-test-selector="health-label"] .pill').hasClass('pill--red'),
      'red pill is rendered'
    );

    assert.stringIncludes(
      this.$('[data-test-selector="health-label"]').text(),
      'Unstable',
      'stream health displays "Unstable"'
    );

    assert.stringIncludes(
      this.$('[data-test-selector="health-reason"]').eq(0).text(),
      'Incompatible audio codec detected',
      'health reason code 1001 translates to incompatible audio codec'
    );

    assert.stringIncludes(
      this.$('[data-test-selector="health-reason"]').eq(1).text(),
      'Incompatible video codec detected',
      'health reason code 1002 translates to incompatible video codec'
    );

    assert.stringIncludes(
      this.$('[data-test-selector="health-reason"]').eq(2).text(),
      'Poor network connection detected',
      'health reason code 1006 translates to poor network connection'
    );

    done();
  });
});

test('renders stream health for offline channel owner who goes online', function(assert) {
  assert.expect(6);

  let done = assert.async();
  let modelPromise = { id: CHANNEL_LOGIN, _id: CHANNEL_ID };

  let ingestServiceStub = Service.extend({
    getBitrate() {
      return RSVP.resolve({
        Channel: CHANNEL_LOGIN,
        Metric: 'bitrate',
        Results: [
          {
            SessionID: '8ce432b2-6066-4247-843a-7fcd99f70bd3',
            Timestamp: 1476422751,
            Value: 1000.1234
          },
          {
            SessionID: '8ce432b2-6066-4247-843a-7fcd99f70bd3',
            Timestamp: 1476422756,
            Value: 2442.8125
          }
        ]
      });
    }
  });

  this.owner.register('service:ingest', ingestServiceStub);

  this.set('model', modelPromise);
  this.set('isLive', false);

  this.render(hbs`
    {{dashboards/live/stream-health
      channel=model
      isLive=isLive
      isChannelOwner=true
      qualityCode=qualityCode
      reasonCodes=reasonCodes
    }}
  `);

  return wait().then(() => {
    assert.stringIncludes(
      this.$('[data-test-selector="health-label"] .pill').text(),
      'Offline',
      'stream health displays "Offline"'
    );

    this.set('isLive', true);
    this.set('qualityCode', 101);
    this.set('reasonCodes', [1000]);

    return wait();
  }).then(() => {
    assert.elementCount(this.$('[data-test-selector="stream-test-button"]'), 0, 'stream test button is NOT rendered');

    assert.elementCount(
      this.$('[data-test-selector="bitrate"] canvas'),
      1,
      'bitrate chart is rendered'
    );

    assert.stringIncludes(
      this.$('[data-test-selector="latest-bitrate"]').text(),
      '2,443kb/s',
      'bitrate is correct'
    );

    assert.ok(
      this.$('[data-test-selector="health-label"] .pill').hasClass('pill--green'),
      'green pill is rendered'
    );

    assert.stringIncludes(
      this.$('[data-test-selector="health-label"]').text(),
      'Excellent',
      'stream health displays "Excellent"'
    );

    done();
  });
});
