/**
 * Extract request/response XML from RR response/result shapes.
 * @param rrObj
 * @returns {{requestXml: string|null, responseXml: string|null}}
 */
const extractRRXmlPair = (rrObj) => {
  const xml = rrObj?.xml ?? rrObj?.meta?.xml;

  let requestXml = null;
  let responseXml = null;

  if (typeof xml === "string") {
    requestXml = xml;
  } else {
    if (typeof xml?.request === "string") requestXml = xml.request;
    else if (typeof xml?.req === "string") requestXml = xml.req;
    else if (typeof xml?.starXml === "string") requestXml = xml.starXml;
    if (typeof xml?.response === "string") responseXml = xml.response;
  }

  if (!requestXml && typeof rrObj?.requestXml === "string") requestXml = rrObj.requestXml;
  if (!requestXml && typeof rrObj?.meta?.requestXml === "string") requestXml = rrObj.meta.requestXml;
  if (!requestXml && typeof rrObj?.meta?.reqXml === "string") requestXml = rrObj.meta.reqXml;
  if (!requestXml && typeof rrObj?.meta?.request === "string") requestXml = rrObj.meta.request;
  if (!responseXml && typeof rrObj?.responseXml === "string") responseXml = rrObj.responseXml;
  if (!responseXml && typeof rrObj?.meta?.responseXml === "string") responseXml = rrObj.meta.responseXml;
  if (!responseXml && typeof rrObj?.meta?.resXml === "string") responseXml = rrObj.meta.resXml;
  if (!responseXml && typeof rrObj?.meta?.response === "string") responseXml = rrObj.meta.response;

  // If wrapped HTTP response data contains raw XML, surface it.
  if (!responseXml && typeof rrObj?.response?.data === "string") {
    const xmlData = rrObj.response.data.trim();
    if (xmlData.startsWith("<")) responseXml = xmlData;
  }

  // Try one level down when errors are wrapped.
  if ((!requestXml || !responseXml) && rrObj?.cause && rrObj.cause !== rrObj) {
    const nested = extractRRXmlPair(rrObj.cause);
    if (!requestXml) requestXml = nested.requestXml;
    if (!responseXml) responseXml = nested.responseXml;
  }

  return { requestXml, responseXml };
};

/**
 * Add Reynolds request/response XML to RR log metadata when available.
 * @param rrObj
 * @param meta
 * @returns {*}
 */
const withRRRequestXml = (rrObj, meta = {}) => {
  const { requestXml, responseXml } = extractRRXmlPair(rrObj);
  const xmlMeta = {};
  if (requestXml) xmlMeta.requestXml = requestXml;
  if (responseXml) xmlMeta.responseXml = responseXml;
  return Object.keys(xmlMeta).length ? { ...meta, ...xmlMeta } : meta;
};

module.exports = {
  extractRRXmlPair,
  withRRRequestXml
};
