import { stringify } from 'querystring';
import debug from 'debug';

const debugRaw = debug('yfetch:raw');
const debugResult = debug('yfetch:result');
const debugError = debug('yfetch:error');

export class YfetchError extends Error {}

export const JSON_HEADER = {
  Accept: 'application/json',
  'Content-Type': 'application/json',
};

// Support simple opts.query , opts.base and opts.url logic
// Support opts.json headers
// return fetch() arguments
export const transformFetchOptions = ({ query, headers, base = '', url = '', ...opts }) => {
  const queryString = stringify(query);
  const urlString = base + url + (queryString ? `?${queryString}` : '');
  const H = opts.json ? JSON_HEADER : {};

  return [urlString, { headers: { ...H, ...headers }, ...opts }];
};

// Support opts.json, send debug yfetch:result
export const transformFetchResult = ({ fetchArgs, ...response }) => {
  if (fetchArgs[1].json) {
    response.body = JSON.parse(response.body);
  }

  debugResult('url: %s - status: %s - body: %O', response.url, response.status, response.body);

  return { ...response, fetchArgs };
};

// Support opts.error
export const transformFetchStatusError = ({ fetchArgs, ...response }) => {
  if (fetchArgs[1].error
      && fetchArgs[1].error.indexOf
      && fetchArgs[1].error.indexOf(response.status) > 0) {
    throw new YfetchError(`Response Code ${response.status} means Error (includes: ${fetchArgs[1].error.join(',')})`);
  }

  return { ...response, fetchArgs };
};

// handle response.text() promise, make response simple, keep response.fetchArgs
// send debug yfetch:raw
const transformForContext = fetchArgs => (response = {}) => {
  const { url, status, statusText, headers = [], ok, size } = response;
  const H = {};

  headers.forEach((v, k) => {
    H[k] = v;
  });

  const job = response.text ? response.text() : Promise.resolve();

  return job
  .then((body) => {
    debugRaw('url: %s - status: %s - size: %s - header: %o - body: %s', url, status, size, H, body);

    return {
      url,
      status,
      statusText,
      ok,
      size,
      body,
      fetchArgs,
      headers: H,
    };
  });
};

// keep error.fetchArgs and error.response , send debug yfetch:error
const transformFetchError = (fetchArgs, response) => (error) => {
  debugError('url: %s - status: %s - size: %s - body: %s - %O', fetchArgs[0], response.status, response.size, response.body, error);
  error.fetchArgs = fetchArgs;
  error.response = response;
  throw error;
};

// Export this for unit testing and mock
export const executeFetch = args => fetch(...args);

// The main yfetch function
export const yfetch = (opts = {}) => {
  const fetchArgs = transformFetchOptions(opts);
  let R = {};

  // module.exports.executeFetch allow jasmine to mock it
  return module.exports.executeFetch(fetchArgs)
  .then(transformForContext(fetchArgs))
  .then(transformFetchResult)
  .then(response => (R = response))
  .then(transformFetchStatusError)
  .catch(transformFetchError(fetchArgs, R));
};

// as default
export default yfetch;

@@ -2245,16 +2245,18 @@
 tchArgs,
+ %7B
  respons
@@ -2256,16 +2256,23 @@
 response
+ = %7B%7D %7D
 ) =%3E (er
@@ -2705,18 +2705,20 @@
 pts);%0A  
-le
+cons
 t R = %7B%7D
@@ -2720,16 +2720,110 @@
  = %7B%7D;%0A%0A
+  const storeResponse = (response) =%3E %7B%0A    R.response = response;%0A    return response;%0A  %7D;%0A%0A
   // mod
@@ -2960,16 +2960,39 @@
 hArgs))%0A
+  .then(storeResponse)%0A
   .then(
@@ -3025,34 +3025,22 @@
 hen(
-response =%3E (R = r
+storeR
 esponse)
 )%0A  
@@ -3035,17 +3035,16 @@
 esponse)
-)
 %0A  .then

fix response assign bug