/* Licensed Materials - Property of IBM
 * 5725-I43 (C) Copyright IBM Corp. 2018. All Rights Reserved.
 * US Government Users Restricted Rights - Use, duplication or
 * disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
 */

 /* author - Srihari Kulkarni | skulkarni@in.ibm.com | Slack - @Srihari */

import {
  NativeModules,
} from 'react-native';

import 'react-native-get-random-values';
import { v4 as uuidv4 } from 'uuid';

var wlResourceRequest = NativeModules.RNWLResourceRequest;

const _mandatoryParam = function(parameterName){ throw new Error('Error: Missing parameter ' + parameterName ); };
const _uuid = uuidv4(); 
/**
 * This class encapsulates a resource request.
 * The resource can be an adapter that is deployed to an instance of MobileFirst Server, or a resource on an external resource server.
 * The class provides several send methods with different inputs for the body of a request.
 * A successful response is any response with a status in the 2xx range from the server.  
 * A response with a 4xx or 5xx status from the server is considered a failure.
 */
class WLResourceRequest{

  /**
   * Create a new ResourceRequest object to fetch data from a resource endpoint. To access a microservice URL such as "http://mybluemix.net/resorts/cities", the Mobile Foundation runtime backend service is configured as follows
   * {"service": "tourpackage",
   * "baseUrl":"http://mybluemix.net/resorts"} 
   * @constructor 
   * @param {string} url - The URL of the resource - either as an absolute URL or a relative URL. 
   * @param {string} method - The HTTP method to call the resource. Use WLResourceRequest.GET, WLResourceRequest.POST, WLResourceRequest.HEAD, WLResourceRequest.PUT, WLResourceRequest.DELETE, WLResourceRequest.OPTIONS, WLResourceRequest.TRACE
   * @param {number} timeout - Optional. The interval in milliseconds after which the call to the resource should time out. The default timeout is 30 seconds.
   * @param {string} scope - Optional. The scope protecting the particular resource. 
   * @param {string} backendServiceName - Name of the backend service configured on server to fetch data from the backend service. For example : tourpackage,
   * @example var request = new WLResourceRequest("cities", WLResourceRequest.GET,30000,undefined,"tourpackage");
   **/
  
  constructor(url = _mandatoryParam('url'), method = _mandatoryParam('method'),
    timeout = 30000, scope = undefined, backendServiceName = undefined) {
    if (backendServiceName !== undefined && (scope !== null || scope !== undefined)) {
       console.warn('The scope parameter will be ignored!');
     }  
    wlResourceRequest.init(_uuid, url, method, timeout, scope, backendServiceName);
  }

  /* Constants */
  static get POST(){
    return "POST"; 
  }
  static get GET(){
    return "GET"; 
  }
  static HEAD(){
    return "HEAD"; 
  }
  static get PUT(){
    return "PUT"; 
  }
  static get DELETE(){
    return "DELETE"; 
  }
  static get OPTIONS(){
    return "OPTIONS"; 
  }
  static get TRACE(){
    return "TRACE"; 
  }
  
  /**
   * Initiate a request to the resource without any content in the body. 
   * @return {Promise<Map, String>} If success, a map with the response from the server. The map contain following key strings.
   * "responseText" - Original response text from the server.
   * "responseJSON" - in case the response is a JSON response, otherwise map will not have the field.
   * "userInfo" - user information.
   * "headers" - Retrieves the headers from the response.
   * "status" - HTTP status from the response
   * If failure, more information about the error.
   */
  async send(){
    var response = await wlResourceRequest.send(_uuid);
    return response; 
  }

  /**
   * Initiate a request to the resource with the specified JSON content in the body. 
   * @param {Object} jsonObject - The body of the request in JSON format.
   * @return {Promise<Map, String>} If success, a map with the response from the server. The map contain following key strings.
   * "responseText" - Original response text from the server.
   * "responseJSON" - in case the response is a JSON response, otherwise map will not have the field.
   * "userInfo" - user information.
   * "headers" - Retrieves the headers from the response.
   * "status" - HTTP status from the response
   * If failure, more information about the error.
   */
  async sendWithJSON(jsonObject = _mandatoryParam('jsonObject')){
    var response = await wlResourceRequest.sendWithJSON(_uuid,jsonObject);
    return response; 
  }

  /**
   * Initiate a request to the resource with the specified form parameters in the body. 
   * @param {Object} formParams - The JSON object of form parameters in name-value pairs 
   * @return {Promise<Map, String>} If success, a map with the response from the server. The map contain following key strings.
   * "responseText" - Original response text from the server.
   * "responseJSON" - in case the response is a JSON response, otherwise map will not have the field.
   * "userInfo" - user information.
   * "headers" - Retrieves the headers from the response.
   * "status" - HTTP status from the response
   * If failure, more information about the error.
   */
  async sendWithFormParameters(formParams = _mandatoryParam('formParams')){
    var response = await wlResourceRequest.sendWithFormParameters(_uuid,formParams);
    return response; 
  }

  /**
   * Initiate a request to the resource with raw text in the body. 
   * @param {string} body - The body that is part of the request. 
   * @return {Promise<Map, String>} If success, a map with the response from the server.The map contain following key strings.
   * "responseText" - Original response text from the server.
   * "responseJSON" - in case the response is a JSON response, otherwise map will not have the field.
   * "userInfo" - user information.
   * "headers" - Retrieves the headers from the response.
   * "status" - HTTP status from the response
   * If failure, more information about the error.
   */
  async sendWithRequestBody(body = _mandatoryParam('body')){
    var response = await wlResourceRequest.sendWithRequestBody(_uuid,body);
    return response; 
  }

  /**
   * Get the HTTP method of this resource request. 
   * @return {Promise<string>} The HTTP method of the resource request. 
   */
  async getMethod(){
    return await wlResourceRequest.getMethod(_uuid);
  }

  /**
   * Adds a header to this resource request.
   * This method allows response headers to have multiple values.
   * @param {string} name  - The name of the header to add to the request. 
   * @param {string} value - The value of the header to add to the request. 
   */
  addHeader(name= _mandatoryParam('name'), value= _mandatoryParam('value')){
    wlResourceRequest.addHeader(_uuid,name, value);
  }

  /**
   * Set the query parameters that should be added to this request. 
   * @param {Object} params - A JSON object containing name value pairs of query parameters that should be added to this request. 
   */
  setQueryParameters(params = _mandatoryParam('params')) { 
    wlResourceRequest.setQueryParameters(_uuid,params);
  }

  /**
   * Get all the query parameters that are added to this request.
   * @return {Promise<Object>} A JSON object with query parameters 
   */
  async getQueryParameters(){
    return await wlResourceRequest.getQueryParameters(_uuid); 
  }
  
  /**
   * Get the query string of this request. 
   * @return {Promise<string>} A string containing the query parameters as a query string. 
   */
  async getQueryString(){
    return await wlResourceRequest.getQueryString(_uuid); 
  }
  
  /**
   * Get a list of all the headers added to this request
   * @return {Promise<Object>} A list of all HTTP headers that are added to this request. Note that each header can have one or more values. 
   */
  async getAllHeaders(){
    var headers = await wlResourceRequest.getAllHeaders(_uuid); 
    return headers;
  }

  /**
   * Get a list of values for a given header
   * @param {string} headerName - The name of the header
   * @return {Promise<Array>} - An array of values for the given header name. 
   */
  async getHeaders(headerName = _mandatoryParam('headerName')){
    var headers = await wlResourceRequest.getHeaders(_uuid,headerName); 
    return headers;
  }

  /**
   * Sets the specified headers for this resource request.
   * For a header that is already set, the new value overwrites the previous value.
   * @param {Object} headers - A JSON object containing a map of all headers to be set for this request. 
   */
  setHeaders(headers){
    wlResourceRequest.setHeaders(_uuid,headers); 
    
  }

  /**
   * Removes headers with the specified name for this resource request.
   * @param {string} headerName - The name of the header to remove. 
   */
  removeHeaders(headerName = _mandatoryParam('headerName')){
    wlResourceRequest.removeHeaders(_uuid, headerName); 
  }

  /**
   * Sets the expiration period (timeout) for this resource request.
   * @param {number} timeoutInMilliseconds - The timeout in milliseconds
   */
  setTimeout(timeoutInMilliseconds = _mandatoryParam('timeoutInMilliseconds')){
    wlResourceRequest.setTimeout(_uuid, timeoutInMilliseconds);
  }

  /**
   * Returns the URL for this resource request.
   * @return {string} The absolute URL of the resource request.
   */
  async getUrl(){
    return wlResourceRequest.getUrl(_uuid);
  }

  /**
   * Get the timeout for this resource request. 
   * @return {number} - The timeout of this request in milliseconds. 
   */
  async getTimeout(){
    return await wlResourceRequest.getTimeout(_uuid);
  }
}

export default  WLResourceRequest
