/* 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:true */

var loop = loop || {};
loop.FeedbackAPIClient = (function($, _) {
  "use strict";

  /**
   * Feedback API client. Sends feedback data to an input.mozilla.com compatible
   * API.
   *
   * @param {String} baseUrl  Base API url (required)
   * @param {Object} defaults Defaults field values for that client.
   *
   * Required defaults:
   * - {String} product Product name (required)
   *
   * Optional defaults:
   * - {String} platform   Platform name, eg. "Windows 8", "Android", "Linux"
   * - {String} version    Product version, eg. "22b2", "1.1"
   * - {String} channel    Product channel, eg. "stable", "beta"
   * - {String} user_agent eg. Mozilla/5.0 (Mobile; rv:18.0) Gecko/18.0 Firefox/18.0
   *
   * @link  http://fjord.readthedocs.org/en/latest/api.html
   */
  function FeedbackAPIClient(baseUrl, defaults) {
    this.baseUrl = baseUrl;
    if (!this.baseUrl) {
      throw new Error("Missing required 'baseUrl' argument.");
    }

    this.defaults = defaults || {};
    // required defaults checks
    if (!this.defaults.hasOwnProperty("product")) {
      throw new Error("Missing required 'product' default.");
    }
  }

  FeedbackAPIClient.prototype = {
    /**
     * Supported field names by the feedback API.
     * @type {Array}
     */
    _supportedFields: ["happy",
                       "category",
                       "description",
                       "product",
                       "platform",
                       "version",
                       "channel",
                       "user_agent",
                       "url"],

    /**
     * Creates a formatted payload object compliant with the Feedback API spec
     * against validated field data.
     *
     * @param  {Object} fields Feedback initial values.
     * @return {Object}        Formatted payload object.
     * @throws {Error}         If provided values are invalid
     */
    _createPayload: function(fields) {
      if (typeof fields !== "object") {
        throw new Error("Invalid feedback data provided.");
      }

      Object.keys(fields).forEach(function(name) {
        if (this._supportedFields.indexOf(name) === -1) {
          throw new Error("Unsupported field " + name);
        }
      }, this);

      // Payload is basically defaults + fields merged in
      var payload = _.extend({}, this.defaults, fields);

      // Default description field value
      if (!fields.description) {
        payload.description = (fields.happy ? "Happy" : "Sad") + " User";
      }

      return payload;
    },

    /**
     * Sends feedback data.
     *
     * @param  {Object}   fields Feedback form data.
     * @param  {Function} cb     Callback(err, result)
     */
    send: function(fields, cb) {
      var req = $.ajax({
        url:         this.baseUrl,
        method:      "POST",
        contentType: "application/json",
        dataType:    "json",
        data: JSON.stringify(this._createPayload(fields))
      });

      req.done(function(result) {
        console.info("User feedback data have been submitted", result);
        cb(null, result);
      });

      req.fail(function(jqXHR, textStatus, errorThrown) {
        var message = "Error posting user feedback data";
        var httpError = jqXHR.status + " " + errorThrown;
        cb(new Error(message + ": " + httpError + "; " +
                     (jqXHR.responseJSON && jqXHR.responseJSON.detail || "")));
      });
    }
  };

  return FeedbackAPIClient;
})(jQuery, _);
