// pnrDivide.service.js
"use strict";
/**
 * pnrDivide.service.js
 *
 * Handles ProviderReservationDivideReq for ALL passenger combinations:
 *
 *   Single passenger  : { BookingTravelerRefKey: "KEY1" }
 *   ADT + INF pair    : { BookingTravelerRefKey: ["ADT_KEY", "INF_KEY"] }
 *   Multiple pax      : { BookingTravelerRefKey: ["KEY1", "KEY2", "KEY3"] }
 *
 * INF RULE (enforced by Travelport):
 *   INF must ALWAYS be divided with its accompanying ADT.
 *   Dividing INF alone or ADT alone (when INF is linked) is rejected.
 */

const axios  = require("axios");
const xml2js = require("xml2js");

const parser = new xml2js.Parser({
  explicitArray: false,
  tagNameProcessors:  [xml2js.processors.stripPrefix],
  attrNameProcessors: [xml2js.processors.stripPrefix],
  mergeAttrs:   true,
  ignoreAttrs:  false,
});

// =============================================================================
// Extract child locators from ProviderReservationDivideRsp
//
// Actual Travelport response structure:
//   ProviderReservationDivideRsp
//     ├── ParentProviderReservationInfo
//     │     UniversalLocatorCode: "35CI30"  ← parent (unchanged)
//     │     ProviderLocatorCode:  "GBPC18"
//     └── ChildProviderReservationInfo
//           UniversalLocatorCode: "35CI6R"  ← child (newly created) ✅
//           ProviderLocatorCode:  "GBPC3C"
// =============================================================================
const extractChildLocators = (parsedResponse) => {
  const TAG = "[extractChildLocators]";
  try {
    const body = parsedResponse?.Envelope?.Body;
    const rsp  = body?.ProviderReservationDivideRsp;

    if (!rsp) {
      console.warn(`${TAG} ProviderReservationDivideRsp not found`);
      return null;
    }

    const childInfo  = rsp?.ChildProviderReservationInfo;
    const parentInfo = rsp?.ParentProviderReservationInfo;

    if (!childInfo) {
      console.warn(`${TAG} ChildProviderReservationInfo not found`);
      console.warn(`${TAG} Available keys in rsp: ${Object.keys(rsp).join(", ")}`);
      return null;
    }

    const childUniversalLocator  = childInfo?.UniversalLocatorCode || null;
    const childGdsLocator        = childInfo?.ProviderLocatorCode  || null;
    const parentUniversalLocator = parentInfo?.UniversalLocatorCode || null;
    const parentGdsLocator       = parentInfo?.ProviderLocatorCode  || null;

    console.log(`${TAG} Parent : UR=${parentUniversalLocator} | GDS=${parentGdsLocator}`);
    console.log(`${TAG} Child  : UR=${childUniversalLocator}  | GDS=${childGdsLocator}`);

    return {
      childUniversalLocator,
      childGdsLocator,
      parentUniversalLocator,
      parentGdsLocator,
    };
  } catch (err) {
    console.error(`${TAG} Error: ${err.message}`);
    return null;
  }
};

// =============================================================================
// Main divide service
//
// BookingTravelerRefKey can be:
//   string  → single passenger
//   array   → multiple passengers (ADT+INF pair, 2ADT+2INF, etc.)
// =============================================================================
const resDividereq = async (
  UniversalRecordLocatorCode,
  ProviderLocatorCode,
  BookingTravelerRefKey
) => {
  const TAG = "[pnrDivide.service]";
  const traceId = `DIV_${Date.now()}`;

  // Normalise to array — handles single key and multiple keys uniformly
  const travelerKeys = Array.isArray(BookingTravelerRefKey)
    ? BookingTravelerRefKey
    : [BookingTravelerRefKey];

  console.log(`${TAG} Dividing ${travelerKeys.length} traveler(s):`);
  travelerKeys.forEach((k, i) => console.log(`${TAG}   [${i}] ${k}`));

  // Build one <BookingTravelerRef> node per traveler key
  // For ADT+INF: two nodes → Travelport divides both into same child UR
  // For single: one node
  const travelerRefNodes = travelerKeys
    .map((key) => `      <univ:BookingTravelerRef Key="${key}"/>`)
    .join("\n");

  const auth = Buffer.from(
    `${process.env.TRAVELPORT_USERNAME.trim()}:${process.env.TRAVELPORT_PASSWORD.trim()}`
  ).toString("base64");

  const soapBody = `<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <soapenv:Body>
    <univ:ProviderReservationDivideReq
      xmlns:univ="http://www.travelport.com/schema/universal_v54_0"
      xmlns:com="http://www.travelport.com/schema/common_v54_0"
      AuthorizedBy="${process.env.AUTHORIZED_BY}"
      TraceId="${traceId}"
      TargetBranch="${process.env.TARGET_BRANCH.trim()}"
      UniversalRecordLocatorCode="${UniversalRecordLocatorCode}"
      ProviderCode="1G"
      ProviderLocatorCode="${ProviderLocatorCode}"
      CreateChildUniversalRecord="New">
      <com:BillingPointOfSaleInfo OriginApplication="UAPI"/>
${travelerRefNodes}
    </univ:ProviderReservationDivideReq>
  </soapenv:Body>
</soapenv:Envelope>`;

  console.log(`${TAG} SOAP REQUEST:\n${soapBody}`);

  try {
    const response = await axios.post(
      process.env.TRAVELPORT_UR_SERVICE,
      soapBody,
      {
        headers: {
          "Content-Type": "text/xml;charset=UTF-8",
          "SOAPAction":   "",
          Authorization:  `Basic ${auth}`,
        },
      }
    );

    const rawXML        = response.data;
    const jsonResponse  = await parser.parseStringPromise(rawXML);
    const childLocators = extractChildLocators(jsonResponse);

    console.log(`${TAG} Divide successful. childLocators=${JSON.stringify(childLocators)}`);

    return { traceId, rawXML, json: jsonResponse, childLocators };

  } catch (error) {
    const errorData = error.response ? error.response.data : error.message;
    console.error(`${TAG} Error:`, errorData);
    if (typeof errorData === "string" && errorData.includes("Envelope")) {
      const parsedError = await parser.parseStringPromise(errorData);
      throw new Error(JSON.stringify(parsedError));
    }
    throw new Error(errorData);
  }
};

module.exports = { resDividereq, extractChildLocators };