/* global define */
define(
  ["jquery", "underscore", "backbone", "x2js", "models/queryFields/QueryField"],
  function($, _, Backbone, X2JS, QueryField) {
    "use strict";

    /**
     * @class QueryFields
     * @classdesc The collection of queryable fields supported by the the
     * DataONE Solr index, as provided by the DataONE API
     * CNRead.getQueryEngineDescription() function. For more information, see:
     * https://indexer-documentation.readthedocs.io/en/latest/generated/solr_schema.html
     * https://dataone-architecture-documentation.readthedocs.io/en/latest/design/SearchMetadata.html
     * @classcategory Collections/QueryFields
     * @name QueryFields
     * @extends Backbone.Collection
     * @since 2.14.0
     * @constructor
     */
    var QueryFields = Backbone.Collection.extend(
      /** @lends QueryFields.prototype */
      {

        /**
         * The type of Backbone model that this collection comprises
         */
        model: QueryField,

        /**
         * initialize - Creates a new QueryFields collection
         */
        initialize: function(models, options) {
          try {
            if (typeof options === "undefined") {
              var options = {};
            }
          } catch (e) {
            console.log("Failed to initialize a Query Fields collection, error message: " + e);
          }
        },

        /**
         * comparator - A sortBy function that returns the order of each Query
         * Filter model based on its position in the categoriesMap object.
         *
         * @param  {QueryFilter} model The individual Query Filter model
         * @return {number}      A numeric value by which the model should be ordered relative to others.
         */
        comparator: function(model){
          try {
            var categoriesMap = model.categoriesMap();
            var order = _(categoriesMap)
              .chain()
              .pluck("queryFields")
              .flatten()
              .value();
            return order.indexOf(model.get("name"));
          } catch (e) {
            console.log("Failed to sort the Query Fields Collection, error message: " + e);
            return 0
          }
        },

        /**
         * The constructed URL of the collection
         *
         * @returns {string} - The URL to use during fetch
         */
        url: function() {
          try {
            return MetacatUI.appModel.get("queryServiceUrl").replace(/\/\?$/, "");
          } catch (e) {
            return "https://cn.dataone.org/cn/v2/query/solr"
          }
        },

        /**
        * Retrieve the fields from the Coordinating Node
        * @extends Backbone.Collection#fetch
        */
        fetch: function(options) {
          try {
            var fetchOptions = _.extend({dataType: "text"}, options);
            return Backbone.Model.prototype.fetch.call(this, fetchOptions);
          } catch (e) {
            console.log("Failed to fetch Query Fields, error message: " + e);
          }
        },

        /**
         * parse - Parse the XML response from the CN
         *
         * @param  {string} response The queryEngineDescription XML as a string
         * @return {Array}  the Array of Query Field attributes to be added to the collection.
         */
        parse: function(response) {
          try {
            // If the collection is already parsed, just return it
            if ( typeof response === "object" ){
              return response;
            }
            var x2js = new X2JS();
            var responseJSON = x2js.xml_str2json(response);
            if(responseJSON && responseJSON.queryEngineDescription){
              return responseJSON.queryEngineDescription.queryField;
            }
          } catch (e) {
            console.log("Failed to parse Query Fields response, error message: " + e);
          }
        },

        /**
         * getRequiredFilterType - Based on an array of query (Solr) field names, get the
         * type of filter model to use with these fields. For example, if the fields are
         * type text, use a regular filter model. If the fields are tdate, use a
         * dateFilter. If the field types are mixed, then returns the filterType default
         * value in QueryField models.
         *
         * @param  {string[]} fields The list of Query Field names
         * @return {string} The nodeName of the filter model to use (one of the four types
         * of fields that are set in {@link QueryField#filterTypesMap})
         */
         getRequiredFilterType: function (fields) {
          try {
            var types = [],
              // When fields is empty or are different types
              defaultFilterType = MetacatUI.queryFields.models[0].defaults().filterType;

            if (!fields || fields.length === 0 || fields[0] === "") {
              return defaultFilterType
            }

            fields.forEach((newField, i) => {
              var fieldModel = MetacatUI.queryFields.findWhere({ name: newField });
                types.push(fieldModel.get("filterType"));
            });

            // Test of all the fields are of the same type
            var allEqual = types.every((val, i, arr) => val === arr[0]);

            if (allEqual) {
              return types[0]
            } else {
              return defaultFilterType
            }

          } catch (e) {
            console.log("Failed to detect the required filter type in a Query Fields" +
              " Collection, error message: " + e);
          }
        },

      });
    return QueryFields;
  });
