var inflection = require('inflection');
var pathProxy = require('path-proxy');
var Q = require('q');

var noop = function () {
};

var Builder = function (baseObj, resources) {
  this.baseObj = baseObj;
  this.resources = resources;
};

Builder.prototype.build = function () {
  var self = this;
  Object.keys(this.resources).forEach(function (key) {
    //console.log('building ' + key);
    self.buildResource(self.resources[key]);
  });
};

Builder.prototype.buildResource = function (resource) {
  resource.links.forEach(this.buildAction, this);
};

Builder.prototype.buildAction = function (action) {
  var actionName = action.title;
  var properties = action.properties;
  var requiredProps = action.required;

  // HACKY special case for members bulk add and send MIME endpoints
  var path = action.href.replace(/\.json/gi, '').replace(/\.mime/gi, '');
  var constructor = pathProxy.pathProxy(this.baseObj, path);

  constructor.prototype[getName(actionName)] = function (data, fn) {
    var deferred = Q.defer();

    var requestPath = action.href;
    var pathParams = action.href.match(/{[^}]+}/g) || [];

    if (typeof data === 'function') {
      fn = data;
      data = undefined;
    }

    if (!fn) fn = noop;

    var err;

    if (this.params.length !== pathParams.length) {
      err = new Error('Invalid number of params in path (expected ' + pathParams.length + ', got ' + this.params.length + ').');
      return rejectError(err, deferred, fn);
    }

    this.params.forEach(function (param) {
      requestPath = requestPath.replace(/{[^}]+}/, param);
    });

    // check required payload properties
    if (requiredProps && requiredProps.length > 0) {
      if (!data) {
        err = new Error('Missing parameters.');
      }
      else {
        for (var i = 0; i < requiredProps.length; i++) {
          var prop = requiredProps[i];
          if (typeof data[prop] === 'undefined') {
            err = new Error('Missing parameter \'' + prop + '\'');
            break;
          }
        }
      }
    }

    if (err) {
      return rejectError(err, deferred, fn);
    }

    // check payload property types
    for (var key in properties) {
      if (data && data[key]) {
        var type = properties[key].type;
        var dataType = Array.isArray(data[key]) ? 'array' : typeof data[key];
        if (Array.isArray(type)) {
          if (type.indexOf(dataType) === -1) {
            err = new Error('Invalid parameter type. ' + key + ' must be of type: ' + type + '.');
            break;
          }
        }
        else if (dataType !== type) {
          err = new Error('Invalid parameter type. ' + key + ' must be of type: ' + type + '.');
          break;
        }
      }
    }

    if (err) {
      return rejectError(err, deferred, fn);
    }

    this.client = this.base;
    return this.client.request(action.method, requestPath, data, fn);
  };
}
;

function rejectError(err, deferred, fn) {
  deferred.reject(err);
  fn(err);
  return deferred.promise;
}

function getName(name) {
  name = name.toLowerCase();
  name = inflection.dasherize(name).replace(/-/g, '_');
  name = inflection.camelize(name, true);

  return name;
}

exports.build = function (baseObj, resources) {
  var b = new Builder(baseObj, resources);
  b.build();
};




