# Source: mercadopago-support.js

    var pack = require('../package');
    var configurations = require('./configurations');
    var requestManager = require('./request-manager');
    var paymentModule = require('./resources/payment');
    var collectionsModule = require('./resources/collections');
    var preapprovalModule = require('./resources/preapproval');
    var preferencesModule = require('./resources/preferences');
    var preConditions = require('./precondition');
    var ipnModule = require('./resources/ipn');

    module.exports = function () {
      /**
       * Show Warning for method deprecation
       */
      function showWarning() {
        var method = showWarning.caller.name;
        if (!configurations.areTestsRunnning()) {
          console.warn('This method (' + method + ') is deprecated and its going to be remove on next versions');
        }
      }

      /**
       * Enabled or disabled sandbox
       * @param enabled
       */
      function sandboxMode(enabled) {
        showWarning();
        configurations.sandbox = (enabled !== undefined) ? (enabled === true) : configurations.sandbox;
      }

      /**
       * Get access_token using the client_id and client_secret configure
       * @param callback
       * @returns {string}
       */
      function getAccessToken() {
        var callback = preConditions.getCallback(arguments[arguments.length - 1]);

        showWarning();

        return requestManager.generateAccessToken(callback);
      }

      /**
       * Execute a GET operation (Used like a rest client)
       * @param uri
       * @returns {Thenable<U>|*|{anyOf}}
       */
      function getRest(uri) {
        var callback = preConditions.getCallback(arguments[arguments.length - 1]);
        var options;

        showWarning();

        options = {
          path: uri,
          method: 'GET',
          config: {
            qs: (arguments[1] !== undefined && typeof arguments[1] !== 'function') ? arguments[1] : {}
          }
        };

        return requestManager.generateAccessToken(function (err) {
          // Return callback if an error ocurr getting the access_token
          if (err) return callback.apply(null, [err, null]);
          return false;
        }).then(function (accessToken) {
          options.access_token = accessToken;
          return requestManager.exec(options, callback);
        });
      }

      /**
       * Execute a POST operation (Used like a rest client)
       * @param uri
       * @returns {Thenable<U>|*|{anyOf}}
       */
      function postRest(uri) {
        var callback = preConditions.getCallback(arguments[arguments.length - 1]);
        var options;

        showWarning();

        options = {
          path: uri,
          method: 'POST',
          payload: (arguments[1] !== undefined && typeof arguments[1] !== 'function') ? arguments[1] : {},
          config: {
            qs: (arguments[2] !== undefined && typeof arguments[2] !== 'function') ? arguments[2] : {}
          }
        };

        return requestManager.generateAccessToken(function (err) {
          // Return callback if an error ocurr getting the access_token
          if (err) return callback.apply(null, [err, null]);
          return false;
        }).then(function (accessToken) {
          options.access_token = accessToken;
          return requestManager.exec(options, callback);
        });
      }

      /**
       * Execute a PUT operation (Used like a rest client)
       * @param uri
       * @returns {Thenable<U>|*|{anyOf}}
       */
      function putRest(uri) {
        var callback = preConditions.getCallback(arguments[arguments.length - 1]);
        var options;

        showWarning();

        options = {
          path: uri,
          method: 'PUT',
          payload: (arguments[1] !== undefined && typeof arguments[1] !== 'function') ? arguments[1] : {},
          config: {
            qs: (arguments[2] !== undefined && typeof arguments[2] !== 'function') ? arguments[2] : {}
          }
        };

        return requestManager.generateAccessToken(function (err) {
          // Return callback if an error ocurr getting the access_token
          if (err) return callback.apply(null, [err, null]);
          return false;
        }).then(function (accessToken) {
          options.access_token = accessToken;
          return requestManager.exec(options, callback);
        });
      }

      /**
       * Execute a DELETE operation (Used like a rest client)
       * @param uri
       * @returns {Thenable<U>|*|{anyOf}}
       * @private
       */
      function deleteRest(uri) {
        var callback = preConditions.getCallback(arguments[arguments.length - 1]);
        var options;

        showWarning();

        options = {
          path: uri,
          method: 'DELETE',
          config: {
            qs: (arguments[1] !== undefined && typeof arguments[1] !== 'function') ? arguments[1] : {}
          }
        };

        return requestManager.generateAccessToken(function (err) {
          // Return callback if an error ocurr getting the access_token
          if (err) return callback.apply(null, [err, null]);
          return false;
        }).then(function (accessToken) {
          options.access_token = accessToken;
          return requestManager.exec(options, callback);
        });
      }

      /**
       * Create a preference using preferenceModule
       * @param preferences
       * @param callback
       * @returns {preferences}
       */
      function createPreference(preferences) {
        var callback = preConditions.getCallback(arguments[arguments.length - 1]);

        showWarning();

        return preferencesModule.create(preferences, callback);
      }

      /**
       * Update a preference using the preferenceModule (Make sure that the id is on the payload)
       * @param id
       * @param preference
       * @param callback
       * @returns {*}
       */
      function updatePreference(id, preference) {
        var callback = preConditions.getCallback(arguments[arguments.length - 1]);

        showWarning();

        // Add the id to the preferece object
        preference.id = id;

        return preferencesModule.update(preference, callback);
      }

      /**
       * Get a preference using preferenceModule
       * @param id
       * @param callback
       * @returns {*}
       */
      function getPreference(id) {
        var callback = preConditions.getCallback(arguments[arguments.length - 1]);

        showWarning();

        return preferencesModule.get(id, callback);
      }

      /**
       * Create a preapproval payment using the preapprovalModule
       * @param preapproval
       * @param callback
       * @returns {preapproval}
       */
      function createPreapprovalPayment(preapproval) {
        var callback = preConditions.getCallback(arguments[arguments.length - 1]);

        showWarning();

        return preapprovalModule.create(preapproval, callback);
      }

      /**
       * Update a preapproval payment using the preapprovalModule (Make sure that the id is on the payload)
       * @param id
       * @param preapproval
       * @param callback
       * @returns {*}
       */
      function updatePreapprovalPayment(id, preapproval) {
        var callback = preConditions.getCallback(arguments[arguments.length - 1]);

        showWarning();

        // Add the id to the preapproval object
        preapproval.id = id;

        return preapprovalModule.update(preapproval, callback);
      }

      /**
       * Get a preapproval payment using the preapprovalModule
       * @param id
       * @param callback
       * @returns {*}
       */
      function getPreapprovalPayment(id) {
        var callback = preConditions.getCallback(arguments[arguments.length - 1]);

        showWarning();

        return preapprovalModule.get(id, callback);
      }

      /**
       * Search for a payment using specific filters (offset and limit). Use the paymentModule
       * @param filters
       * @param offset
       * @param limit
       * @param callback
       */
      function searchPayment(filters, offset, limit) {
        var callback = preConditions.getCallback(arguments[arguments.length - 1]);

        showWarning();

        if (!isNaN(offset)) filters.offset = offset;
        if (!isNaN(limit)) filters.limit = limit;

        return paymentModule.oldSearch({
          qs: filters
        }, callback);
      }

      /**
       * Get a payment using the IPN Module (Before manage method exists on IPN Module)
       * @param id
       * @param callback
       * @returns {*}
       */
      function getPayment(id) {
        var callback = preConditions.getCallback(arguments[arguments.length - 1]);

        showWarning();

        return ipnModule.getPayment(id, callback);
      }

      /**
       * Get a authorized payment using the IPN Module (Before manage method exists on IPN Module)
       * @param id
       * @param callback
       * @returns {*}
       */
      function getAuthorizedPayment(id) {
        var callback = preConditions.getCallback(arguments[arguments.length - 1]);

        showWarning();

        return ipnModule.getAuthorizedPayment(id, callback);
      }

      /**
       * Refund a payment (v0 implementation)
       * @param id
       * @param callback
       * @returns {*}
       */
      function refundPayment(id) {
        var callback = preConditions.getCallback(arguments[arguments.length - 1]);

        showWarning();

        return collectionsModule.put({
          id: id,
          status: 'refunded'
        }, callback);
      }

      /**
       * Cancel a payment (v0 implementation)
       * @param id
       * @param callback
       * @returns {*}
       */
      function cancelPayment(id) {
        var callback = preConditions.getCallback(arguments[arguments.length - 1]);

        showWarning();

        return collectionsModule.put({
          id: id,
          status: 'cancelled'
        }, callback);
      }

      /**
       * Canacel a preapproval payment using the preapprovalModule
       * @param id
       * @param callback
       * @returns {*}
       */
      function cancelPreapprovalPayment(id) {
        var callback = preConditions.getCallback(arguments[arguments.length - 1]);

        showWarning();

        return preapprovalModule.update({
          id: id,
          status: 'cancelled'
        }, callback);
      }

      return {
        sandboxMode: sandboxMode,
        getAccessToken: getAccessToken,
        get: getRest,
        post: postRest,
        put: putRest,
        delete: deleteRest,
        createPreference: createPreference,
        updatePreference: updatePreference,
        getPreference: getPreference,
        createPreapprovalPayment: createPreapprovalPayment,
        updatePreapprovalPayment: updatePreapprovalPayment,
        getPreapprovalPayment: getPreapprovalPayment,
        searchPayment: searchPayment,
        getPayment: getPayment,
        getPaymentInfo: getPayment,
        getAuthorizedPayment: getAuthorizedPayment,
        refundPayment: refundPayment,
        cancelPayment: cancelPayment,
        cancelPreapprovalPayment: cancelPreapprovalPayment,
        version: pack.version
      };
    };