const xml2js = require("xml2js");

const parser = new xml2js.Parser({
  explicitArray: false,
  ignoreAttrs: false,
});

// Industry standard delay threshold
const DELAY_THRESHOLD_MINUTES = 15;

function minutesDiff(later, earlier) {
  if (!later || !earlier) return 0;
  return Math.round((new Date(later) - new Date(earlier)) / 60000);
}

function deriveFlightStatus(detailAttrs = {}) {
  const scheduledDep = detailAttrs.ScheduledDepartureTime;
  const estimatedDep = detailAttrs.EstimatedDepartureTime;
  const actualDep = detailAttrs.ActualDepartureTime;

  const scheduledArr = detailAttrs.ScheduledArrivalTime;
  const actualArr = detailAttrs.ActualArrivalTime;

  // Best-effort cancellation detection
  if (
    detailAttrs.FlightStatus === "CANCELLED" ||
    detailAttrs.Status === "CANCELLED" ||
    detailAttrs.Cancelled === "true"
  ) {
    return {
      status: "CANCELLED",
      delayMinutes: null,
      basis: "CARRIER_STATUS",
    };
  }

  // Arrived
  if (actualArr && scheduledArr) {
    return {
      status: "ARRIVED",
      delayMinutes: minutesDiff(actualArr, scheduledArr),
      basis: "ACTUAL_ARRIVAL",
    };
  }

  //  Departed
  if (actualDep && scheduledDep) {
    return {
      status: "DEPARTED",
      delayMinutes: minutesDiff(actualDep, scheduledDep),
      basis: "ACTUAL_DEPARTURE",
    };
  }

  // Estimated departure → delayed / on-time
  if (estimatedDep && scheduledDep) {
    const delayMinutes = minutesDiff(estimatedDep, scheduledDep);

    return {
      status:
        delayMinutes >= DELAY_THRESHOLD_MINUTES ? "DELAYED" : "ON_TIME",
      delayMinutes,
      basis: "ESTIMATED_DEPARTURE",
    };
  }

  //  Scheduled only
  if (scheduledDep) {
    return {
      status: "SCHEDULED",
      delayMinutes: 0,
      basis: "SCHEDULED_ONLY",
    };
  }

  //  Fallback
  return {
    status: "UNKNOWN",
    delayMinutes: null,
    basis: "INSUFFICIENT_DATA",
  };
}

module.exports = async function parseFlightInfoResponse(soapXml) {
  const parsed = await parser.parseStringPromise(soapXml);

  //  Locate SOAP Envelope safely
  const envelope =
    parsed["SOAP:Envelope"] ||
    parsed["soapenv:Envelope"] ||
    parsed["soap:Envelope"];

  if (!envelope) {
    throw new Error("Invalid SOAP Envelope");
  }

  const body =
    envelope["SOAP:Body"] ||
    envelope["soapenv:Body"] ||
    envelope["soap:Body"];

  //  SOAP Fault handling
  if (body["SOAP:Fault"]) {
    return {
      success: false,
      fault: body["SOAP:Fault"],
    };
  }

  //  Extract response
  const rsp = body["air:FlightInformationRsp"];
  if (!rsp) {
    throw new Error("FlightInformationRsp not found");
  }

  // FlightInfo may be array
  const flightInfoRaw = rsp["air:FlightInfo"];
  const flightInfo = Array.isArray(flightInfoRaw)
    ? flightInfoRaw[0]
    : flightInfoRaw;

  if (!flightInfo) {
    throw new Error("FlightInfo not found");
  }

  const flightAttrs = flightInfo.$ || {};
  const detail = flightInfo["air:FlightInfoDetail"] || {};
  const detailAttrs = detail.$ || {};

  //  Derive status & delay
  const statusInfo = deriveFlightStatus(detailAttrs);

  //  Normalized REST response
  const data = {
    provider: "1G",
    carrier: flightAttrs.Carrier || null,
    flightNumber: flightAttrs.FlightNumber || null,
    origin: flightAttrs.Origin || null,
    destination: flightAttrs.Destination || null,
    departureDate: flightAttrs.DepartureDate || null,

    status: statusInfo.status,
    delayMinutes: statusInfo.delayMinutes,
    statusBasis: statusInfo.basis,

    departure: {
      scheduled: detailAttrs.ScheduledDepartureTime || null,
      estimated: detailAttrs.EstimatedDepartureTime || null,
      actual: detailAttrs.ActualDepartureTime || null,
      gate: detailAttrs.OriginGate || null,
    },

    arrival: {
      scheduled: detailAttrs.ScheduledArrivalTime || null,
      estimated: detailAttrs.EstimatedArrivalTime || null,
      actual: detailAttrs.ActualArrivalTime || null,
      gate: detailAttrs.DestinationGate || null,
    },

    equipment: detailAttrs.Equipment || null,

    liveStatusAvailable: Boolean(
      detailAttrs.ActualDepartureTime ||
      detailAttrs.ActualArrivalTime ||
      detailAttrs.EstimatedDepartureTime ||
      detailAttrs.EstimatedArrivalTime
    ),
  };

  return {
    success: true,
    data,
  };
};
