"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.extractWarningMessages = extractWarningMessages;
exports.formatRequestBodyDoc = formatRequestBodyDoc;
exports.getResponseWithMostSevereStatusCode = void 0;
exports.hasComments = hasComments;
exports.jsonToString = jsonToString;
exports.replaceVariables = void 0;
exports.splitOnUnquotedCommaSpace = splitOnUnquotedCommaSpace;
exports.textFromRequest = textFromRequest;
exports.unescape = unescape;
var _lodash = _interopRequireDefault(require("lodash"));
var _public = require("@kbn/es-ui-shared-plugin/public");
/*
 * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
 * or more contributor license agreements. Licensed under the Elastic License
 * 2.0 and the Server Side Public License, v 1; you may not use this file except
 * in compliance with, at your election, the Elastic License 2.0 or the Server
 * Side Public License, v 1.
 */

const {
  collapseLiteralStrings,
  expandLiteralStrings
} = _public.XJson;
function textFromRequest(request) {
  let data = request.data;
  if (typeof data !== 'string') {
    data = data.join('\n');
  }
  return request.method + ' ' + request.url + '\n' + data;
}
function jsonToString(data, indent) {
  return JSON.stringify(data, null, indent ? 2 : 0);
}
function formatRequestBodyDoc(data, indent) {
  let changed = false;
  const formattedData = [];
  for (let i = 0; i < data.length; i++) {
    const curDoc = data[i];
    try {
      let newDoc = jsonToString(JSON.parse(collapseLiteralStrings(curDoc)), indent);
      if (indent) {
        newDoc = expandLiteralStrings(newDoc);
      }
      changed = changed || newDoc !== curDoc;
      formattedData.push(newDoc);
    } catch (e) {
      // eslint-disable-next-line no-console
      console.log(e);
      formattedData.push(curDoc);
    }
  }
  return {
    changed,
    data: formattedData
  };
}
function hasComments(data) {
  // matches single line and multiline comments
  const re = /(\/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+\/)|(\/\/.*)|(#.*)/;
  return re.test(data);
}
function extractWarningMessages(warnings) {
  // pattern for valid warning header
  const re = /\d{3} [0-9a-zA-Z!#$%&'*+-.^_`|~]+ \"((?:\t| |!|[\x23-\x5b]|[\x5d-\x7e]|[\x80-\xff]|\\\\|\\")*)\"(?: \"[^"]*\")?/;
  // split on any comma that is followed by an even number of quotes
  return _lodash.default.map(splitOnUnquotedCommaSpace(warnings), warning => {
    const match = re.exec(warning);
    // extract the actual warning if there was a match
    return '#! ' + (match !== null ? unescape(match[1]) : warning);
  });
}
function unescape(s) {
  return s.replace(/\\\\/g, '\\').replace(/\\"/g, '"');
}
function splitOnUnquotedCommaSpace(s) {
  let quoted = false;
  const arr = [];
  let buffer = '';
  let i = 0;
  while (i < s.length) {
    let token = s.charAt(i++);
    if (token === '\\' && i < s.length) {
      token += s.charAt(i++);
    } else if (token === ',' && i < s.length && s.charAt(i) === ' ') {
      token += s.charAt(i++);
    }
    if (token === '"') {
      quoted = !quoted;
    } else if (!quoted && token === ', ') {
      arr.push(buffer);
      buffer = '';
      continue;
    }
    buffer += token;
  }
  arr.push(buffer);
  return arr;
}

/**
 *  Sorts the request data by statusCode in increasing order and
 *  returns the last one which will be rendered in network request status bar
 */
const getResponseWithMostSevereStatusCode = requestData => {
  if (requestData) {
    return requestData.slice().sort((a, b) => a.response.statusCode - b.response.statusCode).pop();
  }
};
exports.getResponseWithMostSevereStatusCode = getResponseWithMostSevereStatusCode;
const replaceVariables = (requests, variables) => {
  const urlRegex = /\${(\w+)}/g;

  // The forward part '([\\"]?)"' of regex matches '\\"', '""', and '"', but the only
  // last match is preferable. The unwanted ones can be filtered out by checking whether
  // the first capturing group is empty. This functionality is identical to the one
  // achievable by negative lookbehind assertion - i.e. '(?<![\\"])"'
  const bodyRegexSingleQuote = /([\\"]?)"\${(\w+)}"(?!")/g;
  const bodyRegexTripleQuotes = /([\\"]?)"""\${(\w+)}"""(?!")/g;
  return requests.map(req => {
    // safeguard - caller passes any[] from editor's getRequestsInRange() as requests
    if (!req || !req.url || !req.data) {
      return req;
    }
    if (urlRegex.test(req.url)) {
      req.url = req.url.replaceAll(urlRegex, (match, key) => {
        var _variable$value;
        const variable = variables.find(({
          name
        }) => name === key);
        return (_variable$value = variable === null || variable === void 0 ? void 0 : variable.value) !== null && _variable$value !== void 0 ? _variable$value : match;
      });
    }
    req.data = req.data.map(data => {
      if (bodyRegexSingleQuote.test(data)) {
        data = data.replaceAll(bodyRegexSingleQuote, (match, lookbehind, key) => {
          const variable = variables.find(({
            name
          }) => name === key);
          if (!lookbehind && variable) {
            // All values must be stringified to send a successful request to ES.
            const {
              value
            } = variable;
            const isStringifiedObject = value.startsWith('{') && value.endsWith('}');
            if (isStringifiedObject) {
              return value;
            }
            const isStringifiedNumber = !isNaN(parseFloat(value));
            // We need to check uuids as well, since they are also numbers.
            if (isStringifiedNumber && !isUUID(value)) {
              return value;
            }
            const isStringifiedArray = value.startsWith('[') && value.endsWith(']');
            if (isStringifiedArray) {
              return value;
            }
            const isStringifiedBool = value === 'true' || value === 'false';
            if (isStringifiedBool) {
              return value;
            }

            // At this point the value must be an unstringified string, so we have to stringify it.
            // Example: 'stringValue' -> '"stringValue"'
            return JSON.stringify(value);
          }
          return match;
        });
      }
      if (bodyRegexTripleQuotes.test(data)) {
        data = data.replaceAll(bodyRegexTripleQuotes, (match, lookbehind, key) => {
          const variable = variables.find(({
            name
          }) => name === key);
          return !lookbehind && variable !== null && variable !== void 0 && variable.value ? '""' + JSON.stringify(variable === null || variable === void 0 ? void 0 : variable.value) + '""' : match;
        });
      }
      return data;
    });
    return req;
  });
};
exports.replaceVariables = replaceVariables;
const isUUID = val => {
  return typeof val === 'string' && val.match(/[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}/);
};