"use strict";

var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault").default;
exports.__esModule = true;
exports.applySecurities = applySecurities;
exports.default = buildRequest;
var _ramdaAdjunct = require("ramda-adjunct");
var _btoaNode = _interopRequireDefault(require("../../helpers/btoa.node.js"));
// This function runs after the common function,
// `src/execute/index.js#buildRequest`

function buildRequest(options, req) {
  const {
    operation,
    requestBody,
    securities,
    spec,
    attachContentTypeForEmptyPayload
  } = options;
  let {
    requestContentType
  } = options;
  req = applySecurities({
    request: req,
    securities,
    operation,
    spec
  });
  const requestBodyDef = operation.requestBody || {};
  const requestBodyMediaTypes = Object.keys(requestBodyDef.content || {});
  const isExplicitContentTypeValid = requestContentType && requestBodyMediaTypes.indexOf(requestContentType) > -1;

  // for OAS3: set the Content-Type
  if (requestBody || attachContentTypeForEmptyPayload) {
    // does the passed requestContentType appear in the requestBody definition?

    if (requestContentType && isExplicitContentTypeValid) {
      req.headers['Content-Type'] = requestContentType;
    } else if (!requestContentType) {
      const firstMediaType = requestBodyMediaTypes[0];
      if (firstMediaType) {
        req.headers['Content-Type'] = firstMediaType;
        requestContentType = firstMediaType;
      }
    }
  } else if (requestContentType && isExplicitContentTypeValid) {
    req.headers['Content-Type'] = requestContentType;
  }
  if (!options.responseContentType && operation.responses) {
    const mediaTypes = Object.entries(operation.responses).filter(([key, value]) => {
      const code = parseInt(key, 10);
      return code >= 200 && code < 300 && (0, _ramdaAdjunct.isPlainObject)(value.content);
    }).reduce((acc, [, value]) => acc.concat(Object.keys(value.content)), []);
    if (mediaTypes.length > 0) {
      req.headers.accept = mediaTypes.join(', ');
    }
  }

  // for OAS3: add requestBody to request
  if (requestBody) {
    if (requestContentType) {
      if (requestBodyMediaTypes.indexOf(requestContentType) > -1) {
        // only attach body if the requestBody has a definition for the
        // contentType that has been explicitly set
        if (requestContentType === 'application/x-www-form-urlencoded' || requestContentType === 'multipart/form-data') {
          if (typeof requestBody === 'object') {
            var _requestBodyDef$conte, _requestBodyDef$conte2;
            const encoding = (_requestBodyDef$conte = (_requestBodyDef$conte2 = requestBodyDef.content[requestContentType]) == null ? void 0 : _requestBodyDef$conte2.encoding) != null ? _requestBodyDef$conte : {};
            req.form = {};
            Object.keys(requestBody).forEach(k => {
              let value;
              try {
                value = JSON.parse(requestBody[k]);
              } catch {
                value = requestBody[k];
              }
              req.form[k] = {
                value,
                encoding: encoding[k] || {}
              };
            });
          } else if (typeof requestBody === 'string') {
            var _requestBodyDef$conte3, _requestBodyDef$conte4;
            const encoding = (_requestBodyDef$conte3 = (_requestBodyDef$conte4 = requestBodyDef.content[requestContentType]) == null ? void 0 : _requestBodyDef$conte4.encoding) != null ? _requestBodyDef$conte3 : {};
            try {
              req.form = {};
              const form = JSON.parse(requestBody);
              Object.entries(form).forEach(([key, value]) => {
                req.form[key] = {
                  value,
                  encoding: encoding[key] || {}
                };
              });
            } catch {
              req.form = requestBody;
            }
          } else {
            req.form = requestBody;
          }
        } else {
          req.body = requestBody;
        }
      }
    } else {
      req.body = requestBody;
    }
  }
  return req;
}

// Add security values, to operations - that declare their need on them
// Adapted from the Swagger2 implementation
function applySecurities({
  request,
  securities = {},
  operation = {},
  spec
}) {
  var _spec$components;
  const result = {
    ...request
  };
  const {
    authorized = {}
  } = securities;
  const security = operation.security || spec.security || [];
  const isAuthorized = authorized && !!Object.keys(authorized).length;
  const securityDef = (spec == null || (_spec$components = spec.components) == null ? void 0 : _spec$components.securitySchemes) || {};
  result.headers = result.headers || {};
  result.query = result.query || {};
  if (!Object.keys(securities).length || !isAuthorized || !security || Array.isArray(operation.security) && !operation.security.length) {
    return request;
  }
  security.forEach(securityObj => {
    Object.keys(securityObj).forEach(key => {
      const auth = authorized[key];
      const schema = securityDef[key];
      if (!auth) {
        return;
      }
      const value = auth.value || auth;
      const {
        type
      } = schema;
      if (auth) {
        if (type === 'apiKey') {
          if (schema.in === 'query') {
            result.query[schema.name] = value;
          }
          if (schema.in === 'header') {
            result.headers[schema.name] = value;
          }
          if (schema.in === 'cookie') {
            result.cookies[schema.name] = value;
          }
        } else if (type === 'http') {
          if (/^basic$/i.test(schema.scheme)) {
            const username = value.username || '';
            const password = value.password || '';
            const encoded = (0, _btoaNode.default)(`${username}:${password}`);
            result.headers.Authorization = `Basic ${encoded}`;
          }
          if (/^bearer$/i.test(schema.scheme)) {
            result.headers.Authorization = `Bearer ${value}`;
          }
        } else if (type === 'oauth2' || type === 'openIdConnect') {
          const token = auth.token || {};
          const tokenName = schema['x-tokenName'] || 'access_token';
          const tokenValue = token[tokenName];
          let tokenType = token.token_type;
          if (!tokenType || tokenType.toLowerCase() === 'bearer') {
            tokenType = 'Bearer';
          }
          result.headers.Authorization = `${tokenType} ${tokenValue}`;
        }
      }
    });
  });
  return result;
}