const queries = require("../graphql-client/queries");
const Dinero = require("dinero.js");
const moment = require("moment-timezone");
const fs = require("fs");
const storage = require("node-persist");
const _ = require("lodash");
const logger = require("../utils/logger");

const soap = require("soap");
const { sendServerEmail } = require("../email/sendemail");

const entegralEndpoint =
  process.env.NODE_ENV === "production"
    ? "https://ws.entegral.com/RepairOrderFolderService/RepairOrderFolderService.asmx?op=RepairOrderFolderAddRq"
    : "https://uat-ws.armsbusinesssolutions.net/RepairOrderFolderService/RepairOrderFolderService.asmx?WSDL";

const client = require("../graphql-client/graphql-client").client;
const { v4 } = require("uuid");

const momentFormat = "yyyy-MM-DDTHH:mm:ss.SSS";

function pollFunc(fn, timeout, interval) {
  var startTime = new Date().getTime();
  ((interval = interval || 1000), (canPoll = true));

  (function p() {
    canPoll = timeout === 0 ? true : new Date().getTime() - startTime <= timeout;
    if (fn() && canPoll) {
      // ensures the function exucutes
      setTimeout(p, interval);
    }
  })();
}

pollFunc(getEntegralShopData, 0, 5 * 60 * 1000); //Set the metadata to refresh every 5 minutes.

async function getEntegralShopData() {
  // await storage.init({ logging: true });
  // const { bodyshops } = await client.request(queries.GET_ENTEGRAL_SHOPS);
  // logger.log("set-entegral-shops-local-storage", "DEBUG", "API", null, null);
  // await storage.setItem("entegralShops", bodyshops);
  // return true; //Continue execution.
}

exports.default = async (req, res) => {
  res.sendStatus(401);
  return;
  //Query for the List of Bodyshop Clients.
  const job = req.body.event.data.new;
  logger.log("arms-job-update", "DEBUG", "api", job.id, null);

  let allEntegralShops = await storage.getItem("entegralShops");

  if (!allEntegralShops) {
    await getEntegralShopData();
    allEntegralShops = await storage.getItem("entegralShops");
  }

  //Is this job part of an entegral shop?
  const bodyshop = allEntegralShops.find((b) => b.id === job.shopid);
  if (!bodyshop) {
    //This job is not for entegral based shops.

    res.sendStatus(200);
    return;
  }

  if (process.env.NODE_ENV === "production") {
    res.sendStatus(200);
    return;
  }
  //TODO: Check if an update should even be sent.
  if (false) {
    res.sendStatus(200);
    return;
  }

  try {
    const transId = v4(); // Can this actually be the job id?
    let obj = {
      RqUID: transId,
      DocumentInfo: {
        BMSVer: "4.0.0",
        DocumentType: "RO",
        DocumentVerCode: "EM",
        DocumentVerNum: GetSupplementNumber(job.joblines), //TODO Get Supplement Number
        DocumentStatus: GetDocumentstatus(job, bodyshop),
        CreateDateTime: moment().format(momentFormat),
        TransmitDateTime: moment().format(momentFormat) // Omitted from ARMS docs
      },
      EventInfo: {
        AssignmentEvent: {
          CreateDateTime: job.asgn_date && moment(job.asgn_date).format(momentFormat)
        },
        // EstimateEvent: {
        //   UploadDateTime: moment().format(momentFormat),
        // },
        RepairEvent: {
          CreatedDateTime: (job.date_open ? moment(job.date_open).tz(bodyshop.timezone) : moment()).format(
            momentFormat
          ),
          ArrivalDateTime: job.actual_in && moment(job.actual_in).tz(bodyshop.timezone).format(momentFormat),
          ArrivalOdometerReading: job.kmin,
          TargetCompletionDateTime:
            job.scheduled_completion && moment(job.scheduled_completion).tz(bodyshop.timezone).format(momentFormat),
          ActualCompletionDateTime:
            job.actual_completion && moment(job.actual_completion).tz(bodyshop.timezone).format(momentFormat),
          ActualPickUpDateTime:
            job.actual_delivery && moment(job.actual_delivery).tz(bodyshop.timezone).format(momentFormat),
          CloseDateTime: job.date_exported && moment(job.date_exported).tz(bodyshop.timezone).format(momentFormat)
        }
      },
      RepairOrderHeader: {
        AdminInfo: {
          InsuranceCompany: {
            Party: {
              OrgInfo: {
                CompanyName: job.ins_co_nm,
                IDInfo: {
                  IDQualifierCode: "US"
                  //IDNum: 44, // ** Not sure where to get this entegral ID from?
                }
                // Communications: [
                //   {
                //     CommQualifier: "WA",
                //     Address: {
                //       Address1: job.ins_addr1,
                //       Address2: job.ins_addr2,
                //       City: job.ins_city,
                //       StateProvince: job.ins_st,
                //       PostalCode: job.ins_zip,
                //       CountryCode: job.ins_ctry,
                //     },
                //   },
                //   {
                //     CommQualifier: "WP",
                //     CommPhone: job.ins_ph1,
                //   },
                //   {
                //     CommQualifier: "WF",
                //     CommPhone: job.ins_ph2,
                //   },
                // ],
              }
              // ContactInfo: {
              //   ContactJobTitle: "Adjuster",
              //   ContactName: {
              //     FirstName: job.est_ct_fn,
              //     LastName: job.est_ct_ln,
              //   },
              // },
            }
          },
          // InsuranceAgent: {
          //   Party: {
          //     OrgInfo: {
          //       CompanyName: "Nationwide Insurance",
          //       Communications: {
          //         CommQualifier: "WP",
          //         CommPhone: "714-5551212",
          //       },
          //     },
          //     ContactInfo: {
          //       ContactJobTitle: "Insurance Agent",
          //       ContactName: {
          //         FirstName: "Paul",
          //         LastName: "White",
          //       },
          //     },
          //   },
          // },
          // Insured: {
          //   Party: {
          //     PersonInfo: {
          //       PersonName: {
          //         FirstName: job.insd_fn,
          //         LastName: job.insd_ln,
          //       },
          //     },
          //   },
          // },
          Owner: {
            Party: {
              PersonInfo: {
                PersonName: {
                  FirstName: job.ownr_co_nm ? "N/A" : job.ownr_fn,
                  LastName: job.ownr_co_nm ? job.ownr_co_nm : job.ownr_ln
                }
                // Communications: [
                //   {
                //     CommQualifier: "HA",
                //     Address: {
                //       Address1: job.ownr_addr1,

                //       City: job.ownr_city,
                //       StateProvince: job.ownr_st,
                //       PostalCode: job.ownr_zip,
                //       CountryCode: job.ownr_ctry,
                //     },
                //   },
                //   {
                //     CommQualifier: "HP",
                //     CommPhone: job.ownr_ph1,
                //   },
                //   {
                //     CommQualifier: "WP",
                //     CommPhone: job.ownr_ph2,
                //   },
                //   {
                //     CommQualifier: "CP",
                //     CommPhone: job.ownr_ph1,
                //   },
                //   {
                //     CommQualifier: "EM",
                //     CommEmail: job.ownr_ea,
                //   },
                // ],
              }
            }
          },
          // Claimant: {
          //   Party: {
          //     PersonInfo: {
          //       PersonName: {
          //         FirstName: job.clm_ct_fn,
          //         LastName: job.clm_ct_ln,
          //       },
          //     },
          //   },
          //   OwnerInd: true,
          // },
          // Estimator: {
          //   Party: {
          //     PersonInfo: {
          //       PersonName: {
          //         FirstName: job.est_ct_fn,
          //         LastName: job.est_ct_ln,
          //       },
          //       // IDInfo: {
          //       //   IDQualifierCode: "US",
          //       //   IDNum: 2941,
          //       // },
          //     },
          //   },
          // },
          RepairFacility: {
            Party: {
              OrgInfo: {
                CompanyName: process.env.NODE_ENV === "production" ? bodyshop.shopname : "IMEX Test Canadian Shop",
                IDInfo: {
                  IDQualifierCode: "US",
                  IDNum: bodyshop.entegral_id
                }
              }
            }
          }
        },
        RepairOrderIDs: {
          RepairOrderNum: job.ro_number
          //   VendorCode: "C",
          //   EstimateDocumentID: "1223HJ76",
        },
        RepairOrderType: "DirectRepairProgram", //Need to get from Entegral
        //ReferralSourceType: "Yellow Pages",
        VehicleInfo: {
          VINInfo: {
            VIN: {
              VINNum: job.v_vin
            }
          },
          License: {
            LicensePlateNum: job.plate_no
          },
          VehicleDesc: {
            //ProductionDate: "2009-10",
            ModelYear:
              parseInt(job.v_model_yr) < 1900
                ? parseInt(job.v_model_yr) < moment().tz(bodyshop.timezone).format("YY")
                  ? `20${job.v_model_yr}`
                  : `19${job.v_model_yr}`
                : job.v_model_yr,
            MakeDesc: job.v_make_desc,
            ModelName: job.v_model_desc
          }
          // Paint: {
          //   Exterior: {
          //     Color: {
          //       ColorName: job.v_color,
          //       // OEMColorCode: "1M3",
          //     },
          //   },
          // },
          //   Body: {
          //     BodyStyle: "2 Door Convertible",
          //     Trim: {
          //       TrimCode: "1B3",
          //     },
          //   },
          // Condition: {
          //   DrivableInd: job.driveable ? "Y" : "N",
          // },
        },
        ClaimInfo: {
          ClaimNum: job.clm_no,
          PolicyInfo: {
            PolicyNum: job.policy_no
          },
          LossInfo: {
            Facts: {
              LossDateTime:
                job.loss_date &&
                moment(job.loss_date)
                  //.tz(bodyshop.timezone)
                  .format(momentFormat),
              LossDescCode: "Collision",
              PrimaryPOI: {
                POICode: job.area_of_damage && job.area_of_damage.impact1
              },
              SecondaryPOI: {
                POICode: job.area_of_damage && job.area_of_damage.impact2
              }
            },
            TotalLossInd: job.tlos_ind
          }
        }
      },
      ProfileInfo: {
        ProfileName: "ImEX",
        RateInfo: [
          {
            RateType: "PA",
            RateDesc: "Parts Tax",
            TaxInfo: {
              TaxType: "LS",
              TaxableInd: true,
              TaxTierInfo: {
                TierNum: 1,
                Percentage: job.parts_tax_rates.PAN.prt_tax_rt * 100 //TODO Find the best place to take the tax rates for parts.
              }
            }
          },
          {
            RateType: "LA",
            RateDesc: "Labor Tax",
            TaxInfo: {
              TaxType: "LS",
              TaxableInd: true,
              TaxTierInfo: {
                TierNum: 1,
                Percentage: job.parts_tax_rates.PAN.prt_tax_rt * 100 //TODO Find the best place to take the tax rates for labor.
              }
            }
          },
          {
            RateType: "LAB",
            RateDesc: "Body Labor",
            RateTierInfo: {
              TierNum: 1,
              Rate: job.rate_lab
            }
          },
          {
            RateType: "LAS",
            RateDesc: "Structural Labor",
            RateTierInfo: {
              TierNum: 1,
              Rate: job.rate_las
            }
          },
          {
            RateType: "LAR",
            RateDesc: "Refinish Labor",
            RateTierInfo: {
              TierNum: 1,
              Rate: job.rate_lar
            }
          },
          {
            RateType: "LAG",
            RateDesc: "Glass Labor",
            RateTierInfo: {
              TierNum: 1,
              Rate: job.rate_lag
            }
          },
          {
            RateType: "LAF",
            RateDesc: "Frame Labor",
            RateTierInfo: {
              TierNum: 1,
              Rate: job.rate_laf
            }
          },
          {
            RateType: "LAM",
            RateDesc: "Mechancial Labor",
            RateTierInfo: {
              TierNum: 1,
              Rate: job.rate_lam
            }
          },
          {
            RateType: "LAU",
            RateDesc: "User Defined Labor",
            RateTierInfo: {
              TierNum: 1,
              Rate: job.rate_lau
            }
          },
          {
            RateType: "MAPA",
            RateDesc: "Paint Materials",
            RateTierInfo: {
              TierNum: 1,
              Rate: job.rate_mapa,
              ThresholdAmt: 0
            },
            MaterialCalcSettings: {
              CalcMethodCode: 2,
              CalcMaxAmt: 9999.99 //TODO Find threshold amts.
            }
          },
          {
            RateType: "MASH",
            RateDesc: "Shop Materials",
            RateTierInfo: {
              TierNum: 1,
              Rate: job.rate_mash
            },
            MaterialCalcSettings: {
              CalcMethodCode: 4,
              CalcMaxAmt: 9999.99 //TODO Find threshold amounts.
            }
          },
          {
            RateType: "MAHW",
            RateDesc: "Hazardous Wastes Removal",
            RateTierInfo: {
              TierNum: 1,
              Rate: job.rate_mahw
            },
            MaterialCalcSettings: {
              //Todo Capture Calc Settings
              CalcMethodCode: 2,
              CalcMaxAmt: 10
            }
          },
          {
            RateType: "MA2S",
            RateDesc: "Two Stage Paint",
            RateTierInfo: {
              TierNum: 1,
              Rate: job.rate_ma2s
            },
            MaterialCalcSettings: {
              CalcMethodCode: 1,
              CalcMaxAmt: 999999.99
            }
          },
          {
            RateType: "MA2T",
            RateDesc: "Two Tone Paint",
            RateTierInfo: {
              TierNum: 1,
              Rate: job.rate_ma2t
            },
            MaterialCalcSettings: {
              CalcMethodCode: 1,
              CalcMaxAmt: 999999.99
            }
          },
          {
            RateType: "MA3S",
            RateDesc: "Three Stage Paint",
            RateTierInfo: {
              TierNum: 1,
              Rate: job.rate_ma3s
            },
            MaterialCalcSettings: {
              CalcMethodCode: 1,
              CalcMaxAmt: 999999.99
            }
          }
        ]
      },
      //StorageDuration: 17,
      RepairTotalsInfo: {
        LaborTotalsInfo: [
          {
            TotalType: "LAB",
            TotalTypeDesc: "Body Labor",
            TotalHours: job.job_totals.rates.lab.hours,
            TotalAmt: Dinero(job.job_totals.rates.lab.total).toFormat("0.00")
          },
          {
            TotalType: "LAF",
            TotalTypeDesc: "Frame Labor",
            TotalHours: job.job_totals.rates.laf.hours,
            TotalAmt: Dinero(job.job_totals.rates.laf.total).toFormat("0.00")
          },
          {
            TotalType: "LAM",
            TotalTypeDesc: "Mechanical Labor",
            TotalHours: job.job_totals.rates.lam.hours,
            TotalAmt: Dinero(job.job_totals.rates.lam.total).toFormat("0.00")
          },
          {
            TotalType: "LAR",
            TotalTypeDesc: "Refinish Labor",
            TotalHours: job.job_totals.rates.lar.hours,
            TotalAmt: Dinero(job.job_totals.rates.lar.total).toFormat("0.00")
          }
        ],
        PartsTotalsInfo: [
          {
            TotalType: "PAA",
            TotalTypeDesc: "Aftermarket Parts",
            TotalAmt: Dinero(job.job_totals.parts.parts.list.PAA && job.job_totals.parts.parts.list.PAA.total).toFormat(
              "0.00"
            )
          },
          {
            TotalType: "PAC",
            TotalTypeDesc: "Re-Chromed Parts",
            TotalAmt: Dinero(job.job_totals.parts.parts.list.PAC && job.job_totals.parts.parts.list.PAC.total).toFormat(
              "0.00"
            )
          },
          {
            TotalType: "PAG",
            TotalTypeDesc: "Glass Parts",
            TotalAmt: Dinero(job.job_totals.parts.parts.list.PAG && job.job_totals.parts.parts.list.PAG.total).toFormat(
              "0.00"
            )
          },
          {
            TotalType: "PAL",
            TotalTypeDesc: "LKQ/Used Parts",
            TotalAmt: Dinero(job.job_totals.parts.parts.list.PAL && job.job_totals.parts.parts.list.PAL.total).toFormat(
              "0.00"
            )
          },
          {
            TotalType: "PAM",
            TotalTypeDesc: "Remanufactured Parts",
            TotalAmt: Dinero(job.job_totals.parts.parts.list.PAM && job.job_totals.parts.parts.list.PAM.total).toFormat(
              "0.00"
            )
          },
          {
            TotalType: "PAN",
            TotalTypeDesc: "New Parts",
            TotalAmt: Dinero(job.job_totals.parts.parts.list.PAN && job.job_totals.parts.parts.list.PAN.total).toFormat(
              "0.00"
            )
          },
          {
            TotalType: "PAR",
            TotalTypeDesc: "Recored Parts",
            TotalAmt: Dinero(job.job_totals.parts.parts.list.PAR && job.job_totals.parts.parts.list.PAR.total).toFormat(
              "0.00"
            )
          }
        ],
        OtherChargesTotalsInfo: [
          {
            TotalType: "OTSL",
            TotalTypeDesc: "Sublet",
            TotalAmt: Dinero(job.job_totals.parts.sublets.total).toFormat("0.00")
          },
          {
            TotalType: "MAPA",
            TotalTypeDesc: "Paint Materials",
            TotalAmt: Dinero(job.job_totals.rates.mapa.total).toFormat("0.00")
          },
          {
            TotalType: "MASH",
            TotalTypeDesc: "Shop Materials",
            TotalAmt: Dinero(job.job_totals.rates.mash.total).toFormat("0.00")
          },
          // {
          //   TotalType: "MAHW",
          //   TotalTypeDesc: "Hazardous Wastes Removal",
          //   TotalAmt: Dinero(job.job_totals.rates.mahw.total).toFormat(
          //     0.0
          //   ),
          // },
          {
            TotalType: "OTST",
            TotalTypeDesc: "Storage",
            TotalAmt: Dinero(job.job_totals.additional.storage).toFormat("0.00")
          },
          {
            TotalType: "OTTW",
            TotalTypeDesc: "Towing",
            TotalAmt: Dinero(job.job_totals.additional.towing).toFormat("0.00")
          },
          {
            TotalType: "OTAC",
            TotalTypeDesc: "Additional Charges",
            TotalAmt: Dinero(job.job_totals.additional.additionalCosts)
              .add(Dinero(job.job_totals.additional.pvrt))
              .toFormat("0.00")
          }
        ],
        SummaryTotalsInfo: [
          {
            TotalType: "TOT",
            TotalSubType: "TT",
            TotalTypeDesc: "Gross Total",
            TotalAmt: Dinero(job.job_totals.totals.total_repairs).toFormat("0.00")
          },
          {
            TotalType: "TOT",
            TotalSubType: "T2",
            TotalTypeDesc: "Net Total",
            TotalAmt: Dinero(job.job_totals.totals.subtotal).toFormat("0.00")
          },
          {
            TotalType: "TOT",
            TotalSubType: "SM",
            TotalTypeDesc: "Supplement Total",
            TotalAmt: job.cieca_ttl ? job.cieca_ttl.data.supp_amt : Dinero().toFormat("0.00")
          },
          {
            TotalType: "TOT",
            TotalSubType: "F7",
            TotalTypeDesc: "Sales Tax",
            TotalAmt: Dinero(job.job_totals.totals.state_tax).toFormat("0.00")
          },
          {
            TotalType: "TOT",
            TotalSubType: "GST",
            TotalTypeDesc: "GST Tax",
            TotalAmt: Dinero(job.job_totals.totals.federal_tax).toFormat("0.00")
          },
          {
            TotalType: "TOT",
            TotalSubType: "D8",
            TotalTypeDesc: "Bottom Line Discount",
            TotalAmt: Dinero(job.job_totals.additional.adjustments).toFormat("0.00")
          },
          {
            TotalType: "TOT",
            TotalSubType: "D2",
            TotalTypeDesc: "Deductible",
            TotalAmt: Dinero({
              amount: Math.round((job.ded_amt || 0) * 100)
            }).toFormat("0.00")
          },
          {
            TotalType: "TOT",
            TotalSubType: "BTR",
            TotalTypeDesc: "Betterment",
            TotalAmt: Dinero(job.job_totals.totals.custPayable.dep_taxes).toFormat("0.00")
          },
          {
            TotalType: "TOT",
            TotalSubType: "AA",
            TotalTypeDesc: "Appearance Allowance",
            TotalAmt: Dinero().toFormat("0.00")
          },
          {
            TotalType: "TOT",
            TotalSubType: "DEPOSIT",
            TotalTypeDesc: "Deposit",
            TotalAmt: Dinero().toFormat("0.00")
          },
          {
            TotalType: "TOT",
            TotalSubType: "INS",
            TotalTypeDesc: "Insurance Pay",
            TotalAmt: Dinero(job.job_totals.totals.total_repairs)
              .subtract(Dinero(job.job_totals.totals.custPayable.total))
              .toFormat("0.00")
          },
          {
            TotalType: "TOT",
            TotalSubType: "CUST",
            TotalTypeDesc: "Customer Pay",
            TotalAmt: Dinero(job.job_totals.totals.custPayable.total).toFormat("0.00")
          }
        ]
        // RepairTotalsType: 1,
      },
      // RepairLabor: {
      //   LaborAllocations: {
      //     LaborAllocation: [
      //       {
      //         LaborAllocationUUID:
      //           "426cce3a-efa7-44d9-b76e-50b9102c4198",
      //         LaborType: "LAB",
      //         Technician: {
      //           Employee: {
      //             PersonInfo: {
      //               PersonName: {
      //                 FirstName: "Jose",
      //                 LastName: "Gonzalez",
      //               },
      //               IDInfo: {
      //                 IDQualifierCode: "US",
      //                 IDNum: 2987,
      //               },
      //             },
      //           },
      //         },
      //         AllocatedHours: 3.5,
      //       },
      //       {
      //         LaborAllocationUUID:
      //           "426cce3a-efa7-44d9-b76e-50b9102c4199",
      //         LaborType: "LAR",
      //         Technician: {
      //           Employee: {
      //             PersonInfo: {
      //               PersonName: {
      //                 FirstName: "Rcardo",
      //                 LastName: "Himenez",
      //               },
      //               IDInfo: {
      //                 IDQualifierCode: "US",
      //                 IDNum: 2989,
      //               },
      //             },
      //           },
      //         },
      //         AllocatedHours: 5.5,
      //       },
      //     ],
      //   },
      // },
      ProductionStatus: {
        ProductionStage: {
          ProductionStageCode: GetProductionStageCode(job, bodyshop),
          ProductionStageDateTime: moment().tz(bodyshop.timezone).format(momentFormat)
          // ProductionStageStatusComment:
          //   "Going to be painted this afternoon",
        },
        RepairStatus: {
          RepairStatusCode: GetRepairStatusCode(job),
          RepairStatusDateTime: moment().tz(bodyshop.timezone).format(momentFormat)
          // RepairStatusMemo: "Waiting on back ordered parts",
        }
      }
      // RepairOrderNotes: {
      //   RepairOrderNote: {
      //     LineSequenceNum: 1,
      //     Note: "Revision Requested : approved--but needs est separated.8/22/2008 11:58:53 AM",
      //     CreateDateTime: "2008-08-22T11:58:53",
      //     AuthoredBy: {
      //       FirstName: {
      //         "#text": "Elizabeth/FirstName>",
      //         LastName: "Unis",
      //       },
      //     },
      //     RepairOrderNote: {
      //       LineSequenceNum: 2,
      //       Note: "Approved : 8/26/2008 12:21:08 PM",
      //       CreateDateTime: "2008-08-26T12:21:08",
      //       AuthoredBy: {
      //         FirstName: {
      //           "#text": "Elizabeth/FirstName>",
      //           LastName: "Unis",
      //         },
      //       },
      //     },
      //   },
      // },
    };

    deleteNullKeys(obj);

    try {
      const entegralSoapClient = await soap.createClientAsync(entegralEndpoint, {
        ignoredNamespaces: true,
        wsdl_options: {
          //  useEmptyTag: true,
        },
        wsdl_headers: {
          Authorization: `Basic ${new Buffer.from(
            `${process.env.ENTEGRAL_USER}:${process.env.ENTEGRAL_PASSWORD}`
          ).toString("base64")}`
        }
      });

      entegralSoapClient.setSecurity(
        new soap.BasicAuthSecurity(process.env.ENTEGRAL_USER, process.env.ENTEGRAL_PASSWORD)
      );

      const entegralResponse = await entegralSoapClient.RepairOrderFolderAddRqAsync(
        obj,
        function (err, result, rawResponse, soapHeader, rawRequest) {
          fs.writeFileSync(`./logs/arms-request.xml`, rawRequest);
          fs.writeFileSync(`./logs/arms-response.xml`, rawResponse);

          logger.log("arms-job-xml-request", "DEBUG", "api", job.id, {
            xml: rawRequest
          });
          logger.log("arms-job-xml-response", "DEBUG", "api", job.id, {
            xml: rawResponse
          });

          if (err) {
            sendServerEmail({
              subject: `ARMS Update Failed: ${bodyshop.shopname} - ${job.ro_number}`,
              text: `Error: ${JSON.stringify(error)}`
            });
          }

          res.status(200).json(err || result);
        }
      );

      const [result, rawResponse, , rawRequest] = entegralResponse;
    } catch (error) {
      logger.log("arms-failed-job-upload", "ERROR", "api", job.shopid, {
        job: JSON.stringify({ id: job.id, ro_number: job.ro_number }),
        error: error.message || JSON.stringify(error)
      });
      //console.log(error);
    }
  } catch (error) {
    logger.log("arms-failed-job", "ERROR", "api", job.shopid, {
      job: JSON.stringify({ id: job.id, ro_number: job.ro_number }),
      error: error.message || JSON.stringify(error)
    });
  }

  res.sendStatus(200);
  return;
  const allErrors = [];
  try {
    for (const bodyshop of bodyshops) {
      logger.log("arms-start-shop-extract", "DEBUG", "api", bodyshop.id, {
        shopname: bodyshop.shopname
      });
      const erroredJobs = [];
      try {
        const { jobs } = await client.request(queries.ENTEGRAL_EXPORT, {
          bodyshopid: bodyshop.id
        });
        const jobsToPush = [];

        if (erroredJobs.length > 0) {
          logger.log("arms-failed-jobs", "ERROR", "api", bodyshop.id, {
            count: erroredJobs.length,
            jobs: JSON.stringify(erroredJobs.map((j) => j.job.ro_number))
          });
          allErrors = [...allErrors, ...erroredJobs];
        }

        logger.log("arms-end-shop-extract", "DEBUG", "api", bodyshop.id, {
          shopname: bodyshop.shopname
        });

        try {
          const entegralSoapClient = await soap.createClientAsync(entegralEndpoint, {
            ignoredNamespaces: true,
            wsdl_options: {
              //  useEmptyTag: true,
            },
            wsdl_headers: {
              Authorization: `Basic ${new Buffer.from(
                `${process.env.ENTEGRAL_USER}:${process.env.ENTEGRAL_PASSWORD}`
              ).toString("base64")}`
            }
          });

          entegralSoapClient.setSecurity(
            new soap.BasicAuthSecurity(process.env.ENTEGRAL_USER, process.env.ENTEGRAL_PASSWORD)
          );

          const entegralResponse = await entegralSoapClient.RepairOrderFolderAddRqAsync(
            [jobsToPush[0]],
            function (err, result, rawResponse, soapHeader, rawRequest) {
              fs.writeFileSync(`./logs/arms-request.xml`, rawRequest);
              fs.writeFileSync(`./logs/arms-response.xml`, rawResponse);

              res.json(err || result);
            }
          );

          const [result, rawResponse, , rawRequest] = entegralResponse;
        } catch (error) {
          fs.writeFileSync(`./logs/${xmlObj.filename}`, xmlObj.xml);
          //console.log(error);
          logger.log("arms-error-shop", "ERROR", "api", bodyshop.id, {
            error
          });
        }
      } catch (error) {
        //Error at the shop level.
        logger.log("arms-error-shop", "ERROR", "api", bodyshop.id, {
          error
        });

        allErrors.push({
          bodyshopid: bodyshop.id,
          imexshopid: bodyshop.imexshopid,
          fatal: true,
          errors: [error.toString()]
        });
      } finally {
        allErrors.push({
          bodyshopid: bodyshop.id,
          imexshopid: bodyshop.imexshopid,
          errors: erroredJobs
        });
      }
    }

    res.sendStatus(200);
  } catch (error) {
    res.status(200).json(error);
  }
};

function GetSupplementNumber(joblines) {
  if (!joblines) return 0;
  const max = _.max(joblines.map((jl) => parseInt((jl.line_ind || "0").replace(/[^\d.-]/g, ""))));

  return max || 0;
}

function GetDocumentstatus(job, bodyshop) {
  switch (job.status) {
    case bodyshop.md_ro_statuses.default_void:
      return "V";
    case bodyshop.md_ro_statuses.default_invoiced:
    case bodyshop.md_ro_statuses.default_exported:
      return "Z";

    default:
      return "O";
  }
}

function GetRepairStatusCode(job) {
  return "25";
}

function GetProductionStageCode(job, bodyshop) {
  const result = (bodyshop.features?.entegral).find((k) => k.status === job.status);

  return result?.code || "33";
}

function isEmpty(obj) {
  for (var key in obj) return false;

  return true;
}

function deleteNullKeys(app) {
  for (var key in app) {
    if (app[key] !== null && typeof app[key] === "object") {
      deleteNullKeys(app[key]);

      if (isEmpty(app[key])) {
        delete app[key];
      }
    }
    if (app[key] === null) {
      delete app[key];
    }
  }
}
