
function resolveParam(k, value) {
  if (value instanceof Date) {
    value = value.toISOString().slice(0, 10);
  } else if (value === 0) {
    value = "0"
  } else if (value === false) {
    value = "false";
  }
  return encodeURIComponent(k) + '=' + encodeURIComponent(value || "")
}


function prepareQueryParams(params) {
  let query = "";
  if (params) {
    query += "?";

    query += Object.keys(params)
    .filter(k => k && k.length > 0)
    .map(k => {
      let value = params[k];
      if (Array.isArray(value)) {
        return value.map(val => resolveParam(k, val)).join("&");
      }
      return resolveParam(k, value);
    })
    .join('&');
  }

  return query;
}


export default function backendRequest(url, method, options = {}) {
  let {
    params, 
    body,
    upload,
    headers,

    onError,
    parseResponse,
    handleResponse,
    onResponseJson
  } = options;

  let query = prepareQueryParams(params);

  const httpHeaders = new Headers();
  if (!upload && typeof body === "object") {
    body = JSON.stringify(body);
    httpHeaders.append("Content-Type", "application/json;charset=UTF-8");
  }

  if (headers) {
    let header;
    if (Array.isArray(headers)) {
      for (let i = 0; i < headers.length; i++) {
        header = headers[i];
        httpHeaders.append(header.name, header.value);
      }
    } else if (typeof headers === 'object') {
      for (let name in headers) {
        if (headers.hasOwnProperty(name)) {
          httpHeaders.append(name, headers[name]);
        }
      }
    } else {
      httpHeaders.append(headers.name, headers.value);
    }
  }

  const opts = {
    method: method || 'GET',
    headers: httpHeaders,
    mode: 'cors',
    credentials: 'same-origin',
    cache: 'no-store',
    body
  };

	return fetch(`${url}${query}`, opts).then(function(res) {
        //handle 401 response
      	if (res.status === 401) {
          //this is probably handled by the server side - TODO
          window.location.href = '/logout';
      		return;
        } else if (!res.ok) {
          return res.text().then(text => {
            let error = {};
            try {
              error = JSON.parse(text);
            } catch (e) {
              error = { msg: text }
            }
            throw error;
          }); //TODO parse error?
        }

        if (typeof handleResponse === "function") {
          return handleResponse(res);
        }

        return res.text().then(text => {
          //TODO refactor??
          let rheaders = res.headers;

          let headers = {};
          let body = text;

          if (rheaders) {
            for (let pair of rheaders.entries()) {
               headers[pair[0]] = pair[1];
            }        
          }

          if (typeof parseResponse === "function") {
            body = parseResponse(text)
          } else if (body) {
            body = JSON.parse(body);
            if (body && typeof onResponseJson === "function") {
              body = onResponseJson(body);
            }
          }

          return { headers, body };
        })
        
      }).catch((e) => { throw e });
}


export function download(url, options) {
  if (options && options.params) {
    url += prepareQueryParams(options.params);
  }

  var ifrm = document.getElementById("_downloadIframe_");
  if (!ifrm) {
    ifrm = document.createElement("iframe");
    ifrm.setAttribute("id", "_downloadIframe_");
    ifrm.setAttribute("src", url);
    ifrm.style.width = "1px";
    ifrm.style.height = "1px";
    ifrm.style.position = 'fixed';
    ifrm.style.left= "-10px";
    document.body.appendChild(ifrm);
  } else {
    ifrm.setAttribute("src", url);
  }
  
    
};



export function upload(url, file, method) {
    let formData = new FormData();
    formData.append("file", file);
    formData.append("date", new Date().toISOString().slice(0, 10));

    return backendRequest(url, method || 'POST', {
      upload: true,
      body: formData
    });
}