import { test } from 'ember-qunit';
import Component from 'ember-component';
import $ from 'jquery';
import Service from 'ember-service';
import RSVP from 'rsvp';
import hbs from 'htmlbars-inline-precompile';
import moduleForComponent from 'web-client/tests/helpers/module-for-component';

import { FILE_SIZE_LIMIT_BYTES } from 'web-client/components/dashboards/subscription-dash/badges/upload-form/component';
import { BadgesPage } from 'web-client/tests/pages/dashboards/subscription-dash';

const CREATED_BADGE = {
  id: 1,
  required_tenure_months: 12,
  image_1x_url: "#test1",
  image_2x_url: "#test2",
  image_4x_url: "#test4",
  title: "Test Badge Title"
};

const CHANNEL_ID = 9000;

let subscriptionsStub;

moduleForComponent('dashboards/subscription-dash/badges/upload-form', 'Integration | Component | dashboards/subscription-dash/badges/upload form', {
  integration: true,

  beforeEach() {
    this.set('onBadgeCreate', () => {});
    this.set('channelID', CHANNEL_ID);
    this.set('requiredTenureMonths', CREATED_BADGE.required_tenure_months);

    this.$().append('<div id="wormhole-overlays"></div>');

    this.page = BadgesPage.create();
  }
});

test('it renders a valid form', function (assert) {
  assert.expect(4);

  this.render(hbs`
    {{dashboards/subscription-dash/badges/upload-form
      onBadgeCreate=onBadgeCreate
      channelID=channelID
      requiredTenureMonths=requiredTenureMonths}}
  `);

  let $fileInputs = this.$(this.page.subBadgeImagePickerInput());
  let expectedFileSizeKilobytes = Math.floor(FILE_SIZE_LIMIT_BYTES / 1000);

  assert.stringIncludes(
    this.$('p.sub-text:last').text(),
    `Max file size is ${expectedFileSizeKilobytes} KB`,
    'file size constant is converted from bytes to kilobytes'
  );

  assert.equal($fileInputs.eq(0).attr('name'), 'image_1x', 'first <input type="file"> has valid "name" attribute');
  assert.equal($fileInputs.eq(1).attr('name'), 'image_2x', 'second <input type="file"> has valid "name" attribute');
  assert.equal($fileInputs.eq(2).attr('name'), 'image_4x', 'third <input type="file"> has valid "name" attribute');
});

test('submit is enabled after filling in all three <input> fields', function (assert) {
  assert.expect(4);

  this.owner.register('component:dashboards/subscription-dash/badges/badge-image-picker', Component);
  this.owner.register(
    'template:components/dashboards/subscription-dash/badges/badge-image-picker',
    hbs`<input data-test-input onchange={{action updateFile}}>`
  );

  this.render(hbs`
    {{dashboards/subscription-dash/badges/upload-form
      onBadgeCreate=onBadgeCreate
      channelID=channelID
      requiredTenureMonths=requiredTenureMonths}}
  `);

  assert.ok(this.$(this.page.formSubmitButton()).prop('disabled'), 'button is disabled');
  assert.ok(this.$(this.page.formSubmitButton()).hasClass('button--disabled'), 'button has disabled class');

  let $fileInputs = this.$(`${this.page.form()} input[data-test-input]`);

  $fileInputs.each((idx, input) => {
    let $input = $(input);

    $input.val('test');
    $input.change();
  });

  let $submitButton = this.$(this.page.formSubmitButton());

  assert.notOk($submitButton.prop('disabled'), 'button is NOT disabled');
  assert.notOk($submitButton.hasClass('button--disabled'), 'button does NOT have disabled class');
});


test('it renders a confirmation modal on button[type="submit"] click', function (assert) {
  assert.expect(8);

  this.owner.register('component:dashboards/subscription-dash/badges/badge-image-picker', Component);
  this.owner.register(
    'template:components/dashboards/subscription-dash/badges/badge-image-picker',
    hbs`<input data-test-input onchange={{action updateFile}}>`
  );

  this.render(hbs`
    {{dashboards/subscription-dash/badges/upload-form
      onBadgeCreate=onBadgeCreate
      channelID=channelID
      requiredTenureMonths=requiredTenureMonths}}
  `);

  let $fileInputs = this.$(`${this.page.form()} input[data-test-input]`);
  let $submitButton = this.$(this.page.formSubmitButton());

  $fileInputs.each((idx, input) => {
    let $input = $(input);

    $input.val('test');
    $input.change();
  });

  assert.elementCount($(this.page.modal()), 0, 'modal is NOT rendered');

  $submitButton.click();

  assert.elementCount($(this.page.modal()), 1, 'modal is rendered');

  assert.elementText(
    $(`${this.page.modal()} .item p`),
    'By uploading and saving these images, you are confirming that you own all rights to the images.',
    'modal paragraph text is rendered'
  );

  assert.ok($submitButton.prop('disabled'), 'submit button is disabled');
  assert.ok($submitButton.hasClass('button--disabled'), 'submit button has disabled class');

  $(this.page.modalCancelButton()).click();

  assert.elementCount($(this.page.modal()), 0, 'modal is once again NOT rendered');

  assert.notOk($submitButton.prop('disabled'), 'submit button is NOT disabled');
  assert.notOk($submitButton.hasClass('button--disabled'), 'submit button does NOT have disabled class');
});

test('changing the passed-in "requiredTenureMonths" property resets all files', function (assert) {
  assert.expect(9);

  this.owner.register('component:dashboards/subscription-dash/badges/badge-image-picker', Component);
  this.owner.register(
    'template:components/dashboards/subscription-dash/badges/badge-image-picker',
    hbs`<input data-test-input value={{file}} onchange={{action updateFile}}>`
  );

  this.set('image1xFile', null);

  this.render(hbs`
    {{dashboards/subscription-dash/badges/upload-form
      onBadgeCreate=onBadgeCreate
      channelID=channelID
      requiredTenureMonths=requiredTenureMonths
      image1xFile=image1xFile}}
  `);

  let $fileInputs = this.$(`${this.page.form()} input[data-test-input]`);

  assert.notOk($fileInputs.eq(0).attr('value'), 'first <input> has no "value"');
  assert.notOk($fileInputs.eq(1).attr('value'), 'second <input> has no "value"');
  assert.notOk($fileInputs.eq(2).attr('value'), 'third <input> has no "value"');

  this.set('image1xFile', 'test');

  assert.equal($fileInputs.eq(0).attr('value'), 'test', 'first <input> has a valid "value"');
  assert.notOk($fileInputs.eq(1).attr('value'), 'second <input> still has no "value"');
  assert.notOk($fileInputs.eq(2).attr('value'), 'third <input> still has no "value"');

  this.set('requiredTenureMonths', 99);

  $fileInputs = this.$(`${this.page.form()} input[data-test-input]`);

  assert.notOk($fileInputs.eq(0).attr('value'), 'first <input> once again has no "value"');
  assert.notOk($fileInputs.eq(1).attr('value'), 'second <input> still has no "value"');
  assert.notOk($fileInputs.eq(2).attr('value'), 'third <input> still has no "value"');
});

// As of August 31, 2016, `FormData.get()` is an experimental API that is not fully supported
// by all browsers: https://developer.mozilla.org/en-US/docs/Web/API/FormData/get.
//
// When running the test in PhantomJS, `FormData.get()` throws an error as it is undefined.
//
// If `FormData.get()` is available as a function, we include four additional assertions.
// These assertions test for specific values in the form data of the `upload-form` component's
// multipart/form-data AJAX request.
let canTestFormDataValues = (typeof window.FormData.prototype.get === 'function');

test('submitting makes a call on Subscriptions service, invokes closure action, and renders a success notification', function (assert) {
  assert.expect(canTestFormDataValues ? 10 : 6);

  let testInputValue = 'test test test!';

  subscriptionsStub = Service.extend({
    createBadge({ channelID, formData }) {
      assert.equal(channelID, CHANNEL_ID, 'channel ID is correct');
      assert.ok(formData instanceof FormData, 'request data is form data');

      if (canTestFormDataValues) {
        assert.equal(
          formData.get('required_tenure_months'),
          CREATED_BADGE.required_tenure_months,
          'form data "required_tenure_months" value is valid'
        );

        assert.equal(formData.get('image_1x'), testInputValue, 'form data "image_1x" value is valid');
        assert.equal(formData.get('image_2x'), testInputValue, 'form data "image_2x" value is valid');
        assert.equal(formData.get('image_4x'), testInputValue, 'form data "image_4x" value is valid');
      }

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

  this.set('testInputValue', testInputValue);

  this.register('service:subscriptions', subscriptionsStub);

  this.set('onBadgeCreate', (createdBadge) => {
    assert.deepEqual(createdBadge, CREATED_BADGE, 'badge is passed');
  });

  this.render(hbs`
    {{dashboards/subscription-dash/badges/upload-form
      onBadgeCreate=onBadgeCreate
      channelID=channelID
      requiredTenureMonths=requiredTenureMonths
      image1xFile=testInputValue
      image2xFile=testInputValue
      image4xFile=testInputValue}}
  `);

  this.$(this.page.formSubmitButton()).click();

  assert.elementCount($(this.page.modal()), 1, 'modal is rendered');

  $(this.page.modalConfirmButton()).click();

  assert.elementCount($(this.page.modal()), 0, 'modal is NOT rendered');
  assert.didNotify('Badge images successfully saved');
});

test('failing to create a badge renders an error notification', function (assert) {
  assert.expect(1);

  subscriptionsStub = Service.extend({
    createBadge() {
      return RSVP.reject();
    }
  });

  this.register('service:subscriptions', subscriptionsStub);

  this.render(hbs`
    {{dashboards/subscription-dash/badges/upload-form
      onBadgeCreate=onBadgeCreate
      channelID=channelID
      requiredTenureMonths=requiredTenureMonths
      isFormComplete=true}}
  `);

  this.$(this.page.formSubmitButton()).click();
  $(this.page.modalConfirmButton()).click();

  assert.didNotify('Failed to save badge images');
});
