/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

/*global loop, sinon, React */
/* jshint newcap:false */

var expect = chai.expect;
var l10n = navigator.mozL10n || document.mozL10n;
var TestUtils = React.addons.TestUtils;
var sharedActions = loop.shared.actions;
var sharedViews = loop.shared.views;

var FEEDBACK_STATES = loop.store.FEEDBACK_STATES;

describe("loop.shared.views.FeedbackView", function() {
  "use strict";

  var sandbox, comp, dispatcher, fakeFeedbackClient, feedbackStore;

  beforeEach(function() {
    sandbox = sinon.sandbox.create();
    dispatcher = new loop.Dispatcher();
    fakeFeedbackClient = {send: sandbox.stub()};
    feedbackStore = new loop.store.FeedbackStore(dispatcher, {
      feedbackClient: fakeFeedbackClient
    });
    comp = TestUtils.renderIntoDocument(
      React.createElement(sharedViews.FeedbackView, {
        feedbackStore: feedbackStore
      }));
  });

  afterEach(function() {
    sandbox.restore();
  });

  // local test helpers
  function clickHappyFace(comp) {
    var happyFace = comp.getDOMNode().querySelector(".face-happy");
    TestUtils.Simulate.click(happyFace);
  }

  function clickSadFace(comp) {
    var sadFace = comp.getDOMNode().querySelector(".face-sad");
    TestUtils.Simulate.click(sadFace);
  }

  function fillSadFeedbackForm(comp, category, text) {
    TestUtils.Simulate.change(
      comp.getDOMNode().querySelector("[value='" + category + "']"));

    if (text) {
      TestUtils.Simulate.change(
        comp.getDOMNode().querySelector("[name='description']"), {
          target: {value: "fake reason"}
        });
    }
  }

  function submitSadFeedbackForm(comp, category, text) {
    TestUtils.Simulate.submit(comp.getDOMNode().querySelector("form"));
  }

  describe("Happy feedback", function() {
    it("should dispatch a SendFeedback action", function() {
      var dispatch = sandbox.stub(dispatcher, "dispatch");

      clickHappyFace(comp);

      sinon.assert.calledWithMatch(dispatch, new sharedActions.SendFeedback({
        happy: true,
        category: "",
        description: ""
      }));
    });

    it("should thank the user once feedback data is sent", function() {
      feedbackStore.setStoreState({feedbackState: FEEDBACK_STATES.SENT});

      expect(comp.getDOMNode().querySelectorAll(".thank-you")).not.eql(null);
      expect(comp.getDOMNode().querySelector("button.fx-embedded-btn-back"))
        .eql(null);
    });
  });

  describe("Sad feedback", function() {
    it("should bring the user to feedback form when clicking on the sad face",
      function() {
        clickSadFace(comp);

        expect(comp.getDOMNode().querySelectorAll("form")).not.eql(null);
      });

    it("should render a back button", function() {
      feedbackStore.setStoreState({feedbackState: FEEDBACK_STATES.DETAILS});

      expect(comp.getDOMNode().querySelector("button.fx-embedded-btn-back"))
        .not.eql(null);
    });

    it("should reset the view when clicking the back button", function() {
      feedbackStore.setStoreState({feedbackState: FEEDBACK_STATES.DETAILS});

      TestUtils.Simulate.click(
        comp.getDOMNode().querySelector("button.fx-embedded-btn-back"));

      expect(comp.getDOMNode().querySelector(".faces")).not.eql(null);
    });

    it("should disable the form submit button when no category is chosen",
      function() {
        clickSadFace(comp);

        expect(comp.getDOMNode().querySelector("form button").disabled).eql(true);
      });

    it("should disable the form submit button when the 'other' category is " +
       "chosen but no description has been entered yet",
      function() {
        clickSadFace(comp);
        fillSadFeedbackForm(comp, "other");

        expect(comp.getDOMNode().querySelector("form button").disabled).eql(true);
      });

    it("should enable the form submit button when the 'other' category is " +
       "chosen and a description is entered",
      function() {
        clickSadFace(comp);
        fillSadFeedbackForm(comp, "other", "fake");

        expect(comp.getDOMNode().querySelector("form button").disabled).eql(false);
      });

    it("should enable the form submit button once a predefined category is " +
       "chosen",
      function() {
        clickSadFace(comp);

        fillSadFeedbackForm(comp, "confusing");

        expect(comp.getDOMNode().querySelector("form button").disabled).eql(false);
      });

    it("should send feedback data when the form is submitted", function() {
      var dispatch = sandbox.stub(dispatcher, "dispatch");
      feedbackStore.setStoreState({feedbackState: FEEDBACK_STATES.DETAILS});
      fillSadFeedbackForm(comp, "confusing");

      submitSadFeedbackForm(comp);

      sinon.assert.calledOnce(dispatch);
      sinon.assert.calledWithMatch(dispatch, new sharedActions.SendFeedback({
        happy: false,
        category: "confusing",
        description: ""
      }));
    });

    it("should send feedback data when user has entered a custom description",
      function() {
        clickSadFace(comp);

        fillSadFeedbackForm(comp, "other", "fake reason");
        submitSadFeedbackForm(comp);

        sinon.assert.calledOnce(fakeFeedbackClient.send);
        sinon.assert.calledWith(fakeFeedbackClient.send, {
          happy: false,
          category: "other",
          description: "fake reason"
        });
      });

    it("should thank the user when feedback data has been sent", function() {
      fakeFeedbackClient.send = function(data, cb) {
        cb();
      };
      clickSadFace(comp);
      fillSadFeedbackForm(comp, "confusing");
      submitSadFeedbackForm(comp);

      expect(comp.getDOMNode().querySelectorAll(".thank-you")).not.eql(null);
    });
  });
});
