import Component from 'ember-component';
import moduleForComponent from 'web-client/tests/helpers/module-for-component';
import hbs from 'htmlbars-inline-precompile';
import wait from 'ember-test-helpers/wait';
import sinonTest from 'ember-sinon-qunit/test-support/test';
import { test } from 'ember-qunit';
import RSVP from 'rsvp';
import { createMockRouter } from 'web-client/tests/helpers/mock-routing-service';
import UploadsPage from 'web-client/tests/pages/video-manager/uploads';
import { PUBLISH_STRATEGIES } from 'web-client/components/manager/publish-strategy-selector';
import { IMAGE_TYPE_ERROR } from 'web-client/components/video/edit-modal/component';
import moment from 'moment';
import { normalizeVideoId } from 'web-client/utilities/normalize-video-id';
import { assign } from 'ember-platform';

const GENERATED_THUMBNAIL_SRC = '/fixtures/images/stream/2/320x180.jpg';
const CUSTOM_THUMBNAIL_SRC = '/fixtures/images/stream/1/320x180.jpg';

const payload = {
  title: 'Video Title',
  description: null,
  broadcast_type: 'upload',
  type: 'upload',
  status: 'created',
  tag_list: '',
  _id: 'v123',
  game: 'StarCraft II',
  length: 0,
  preview: {
    small: '/fixtures/images/stream/1/52x72.jpg',
    medium: '/fixtures/images/stream/1/320x180.jpg'
  },
  thumbnails: {
    small: [],
    medium: [
      {type: 'generated', url: GENERATED_THUMBNAIL_SRC},
      {type: 'custom', url: CUSTOM_THUMBNAIL_SRC}
    ],
    large: [],
    template: []
  },
  created_at: '2016-07-07T13:10:40Z',
  _links: {
    self: 'http://api.twitch.tv/kraken/videos/v76358832',
    channel: 'http://api.twitch.tv/kraken/channels/%23%3COpenStruct%20id=37519064,%20login=%22golftest120%22,%20name=%22golftest120%22,%20display_name=%22GOLFtest120%22%3E'
  },
  viewable: 'private',
  viewable_at: null,
  channel: {
    name: 'golftest120',
    display_name: 'GOLFtest120'
  }
};

let page;

function findPublishStrategy(strategy) {
  return PUBLISH_STRATEGIES.find((ps) => ps.value === strategy);
}

moduleForComponent('manager/video-uploads/form', 'Integration | Component | manager/video-uploads/form', {
  beforeEach() {
    // no-op this component, which has complicated, global dependencies
    this.register('component:video/thumbnail-cropper', Component.extend());

    // required to render absolute url
    this.register('service:-routing', createMockRouter(routeName => {
      if (routeName === 'videos') {
        let id = normalizeVideoId(payload._id);
        return `/videos/${id}`;
      }
      return '';
    }));

    page = UploadsPage.create({scope: this.$()});

    this.inject.service('store');
    let store = this.get('store');
    let payloadClone = assign({}, payload);

    store.pushPayload('manager/uploader-video', payloadClone);

    this.video = store.peekRecord('manager/uploader-video', 123);
    this.set('video', this.video);
  }
});

test('publish settings show the correct description', function(assert) {
  this.render(hbs`{{manager/video-uploads/form video=video}}`);

  assert.equal(this.video.get('viewable'), 'private', 'video.viewable is correct');
  assert.equal(this.$(page.publishStrategiesSelect()).val(), 'private', 'publish strategy is correct');
  assert.equal(page.publishDescription(), findPublishStrategy('private').description, 'private publish description is correct');

  this.$(page.publishStrategiesSelect()).val('public').trigger('change');

  assert.equal(this.video.get('viewable'), 'public', 'video.viewable is correct');
  assert.equal(this.$(page.publishStrategiesSelect()).val(), 'public', 'publish strategy is correct');
  assert.equal(page.publishDescription(), findPublishStrategy('public').description, 'public publish description is correct');

  this.$(page.publishStrategiesSelect()).val('scheduled').trigger('change');

  assert.equal(this.video.get('viewable'), 'private', 'video.viewable is correct');
  assert.equal(this.$(page.publishStrategiesSelect()).val(), 'scheduled', 'publish strategy is correct');
  assert.equal(page.publishDescription(), findPublishStrategy('scheduled').description, 'scheduled publish description is correct');
});

test('choosing a scheduled publish strategy shows a date picker', function(assert) {
  assert.expect(8);

  this.render(hbs`{{manager/video-uploads/form video=video}}`);

  assert.equal(this.video.get('viewable'), 'private', 'video.viewable is correct');
  assert.equal(this.$(page.publishStrategiesSelect()).val(), 'private', 'publish strategy is correct');
  assert.equal(this.video.get('viewableAt'), null, 'video.viewableAt is null');
  assert.equal(this.$(page.viewableAtDateInput()).length, 0, 'viewableAt input is not present');

  this.$(page.publishStrategiesSelect()).val('scheduled').trigger('change');

  return wait().then(() => {
    assert.ok(this.$(page.viewableAtDateInput()).length, 'viewableAt date input is present');
    assert.notStrictEqual(this.$(page.viewableAtDateInput()).val() !== '', 'viewableAt date input is not blank');
    assert.ok(this.video.get('viewableAt') instanceof Date, 'video.viewableAt is a Date');

    return wait();
  }).then(() => {
    this.$(page.viewableAtTimeInput()).val('3:00pm').change();
    assert.equal(moment(this.video.get('viewableAt')).format('h:mma'), '3:00pm', 'time is set on video');
  });
});

test('should render an absolute URL for the video route', function(assert) {
  this.render(hbs`{{manager/video-uploads/form video=video}}`);

  let $input = this.$('.absolute-url');
  assert.strictEqual($input.val(), `${location.origin}/videos/123`, 'should render the correct url');
});

test('should highlight all text when clicking the absolute-url', function(assert) {
  assert.expect(2);

  this.render(hbs`{{manager/video-uploads/form video=video}}`);

  assert.equal(getSelection().toString(), '', 'should be empty');
  this.$('.absolute-url').click();
  return wait().then(() => {
    assert.equal(getSelection().toString(), `${location.origin}/videos/123`,
      'should highlight all of the <input> text');
  });
});

sinonTest('saving a video with no thumbnail', function(assert) {
  assert.expect(2);

  this.set('onComplete', this.stub());
  this.video.save = this.stub().returns(RSVP.resolve());

  this.render(hbs`{{manager/video-uploads/form video=video onComplete=onComplete}}`);
  this.$('[name=save]').click();

  return wait().then(() => {
    assert.equal(this.video.save.callCount, 1, "video.save() was called once");
    assert.equal(this.get('onComplete').callCount, 1, "onComplete() was called once");
  });
});

sinonTest('saving a video with a new custom thumbnail', function(assert) {
  assert.expect(6);

  this.set('onComplete', this.stub());
  this.set('uploadThumbnail', this.stub().returns(RSVP.resolve()));
  this.video.save = this.stub().returns(RSVP.resolve());

  this.render(hbs`{{manager/video-uploads/form
    video=video
    onComplete=onComplete
    uploadThumbnail=uploadThumbnail
    cropCoordinates=cropCoordinates
    thumbnailFileToUpload=thumbnailFileToUpload}}`);

  return wait().then(() => {
    // File is picked
    this.set('thumbnailFileToUpload', {});

    // Crop coordinates are picked
    this.set('cropCoordinates', {});

    // User saves the form
    this.$('[name=save]').click();

    return wait();
  }).then(() => {
    assert.equal(this.get('uploadThumbnail').callCount, 1, "uploadThumbnail was called");

    let [obj] = this.get('uploadThumbnail').args[0];
    assert.equal(obj.videoId, 123, 'uploadThumbnail called with videoId');
    assert.strictEqual(obj.file, this.get('thumbnailFileToUpload'), 'uploadThumbnail called with file');
    assert.strictEqual(obj.data, this.get('cropCoordinates'), 'uploadThumbnail called with cropCoordinates');

    assert.equal(this.video.save.callCount, 1, "video.save() was called once");
    assert.equal(this.get('onComplete').callCount, 1, "onComplete() was called once");
  });
});

test('removing a custom thumbnail', function(assert) {
  this.render(hbs`{{manager/video-uploads/form video=video}}`);

  assert.deepEqual(
    page.thumbnailsSrc(),
    [GENERATED_THUMBNAIL_SRC, CUSTOM_THUMBNAIL_SRC],
    'Both the generated and custom thumbnails are rendered'
  );
  this.$(page.removeCustomThumbnailButton()).click();

  assert.equal(page.thumbnailIsSelected(GENERATED_THUMBNAIL_SRC), true, 'Generated thumbnail is now selected');
  assert.equal(page.removeCustomThumbnailButton().length, 0, 'The "remove custom thumbnail" button is gone');
  assert.deepEqual(
    page.thumbnailsSrc(),
    [GENERATED_THUMBNAIL_SRC],
    'The custom thumbnail is gone'
  );
});

test('adding a non-image file for the thumbnail', function(assert) {
  assert.expect(2);

  this.render(hbs`{{manager/video-uploads/form video=video}}`);

  let fileChangeEvent = $.Event('change', { __testFiles__: [{ type: 'video/mp4' }] });
  this.$('[data-test-file-picker-button]').trigger(fileChangeEvent);

  assert.equal(
    this.$('[data-test-error-message]').text().trim(),
    IMAGE_TYPE_ERROR,
    'Shows an error message to the user'
  );

  fileChangeEvent = $.Event('change', { __testFiles__: [{ type: 'image/png' }] });
  this.$('[data-test-file-picker-button]').trigger(fileChangeEvent);

  assert.equal(this.$('[data-test-error-message]').length, 0, 'error message goes away');
});

sinonTest('trying to save a video with no title', function(assert) {
  assert.expect(2);
  let errorResponse = {
    status: 400,
    responseJSON: {
      status: 400,
      message: 'Error message'
    }
  };

  this.set('onComplete', this.stub());
  this.video.save = this.stub().returns(RSVP.reject(errorResponse));

  this.render(hbs`{{manager/video-uploads/form video=video onComplete=onComplete}}`);
  this.$('[name=save]').click();

  return wait().then(() => {
    assert.equal(this.$('[data-test-error-message]').text().trim(), 'Error message', 'shows error message');
    assert.equal(this.get('onComplete').callCount, 0, 'onComplete() was not called');
  });
});

sinonTest('rolls back attributes when destroyed', function(assert) {
  assert.expect(2);

  this.set('onComplete', this.stub());
  this.video.rollbackAttributes = this.stub();
  this.set('isShowing', true);

  this.render(hbs`
    {{#if isShowing}}
      {{manager/video-uploads/form video=video onComplete=onComplete}}
    {{/if}}
  `);

  this.$('[name=vod-title]').val('New Title').change();
  assert.equal(this.video.get('title'), 'New Title', 'Updates the title');

  this.set('isShowing', false);
  assert.equal(this.video.rollbackAttributes.callCount, 1, 'called rollbackAttributes');
});
