const handlePaymentValidationError = require("./handlePaymentValidationError");
const {
  GET_JOBID_BY_MERCHANTID_RONUMBER,
  INSERT_PAYMENT_RESPONSE,
  INSERT_NEW_PAYMENT,
  GET_BODYSHOP_BY_MERCHANT_ID
} = require("../../graphql-client/queries");

const { sendTaskEmail } = require("../../email/sendemail");
const getPaymentType = require("./getPaymentType");
const moment = require("moment-timezone");

const gqlClient = require("../../graphql-client/graphql-client").client;

/**
 * @description Handle invoice-based payment processing
 * @param values
 * @param logger
 * @param logMeta
 * @param res
 * @returns {Promise<*>}
 */
const handleInvoiceBasedPayment = async (values, logger, logMeta, res) => {
  // Validate required fields
  if (!values.merchantid) {
    return handlePaymentValidationError(
      res,
      logger,
      "intellipay-postback-no-merchantid",
      "Merchant ID is missing",
      logMeta
    );
  }

  // Fetch job data
  const result = await gqlClient.request(GET_JOBID_BY_MERCHANTID_RONUMBER, {
    merchantID: values.merchantid,
    roNumber: values.invoice
  });

  if (!result?.jobs?.length) {
    // Fetch bodyshop data
    const bodyshop = await gqlClient.request(GET_BODYSHOP_BY_MERCHANT_ID, {
      merchantID: values.merchantid
    });

    if (bodyshop?.bodyshops?.[0]) {
      // Note: changed bodyshops to bodyshop to match query name
      const email = bodyshop.bodyshops[0].email;

      await sendTaskEmail({
        to: email,
        subject: `Failed to Insert Payment`,
        text: `The system has attempted to insert a payment that was generated by your merchant terminal but could not find an associated invoice. Transaction details are below. Please input this payment to your system manually.\n\n${Object.keys(
          values
        )
          .map((key) => `${key}: ${values[key]}`)
          .join("\n")}`
      });
    }

    return handlePaymentValidationError(
      res,
      logger,
      "intellipay-postback-job-not-found",
      "Job not found",
      logMeta,
      200
    );
  }

  const job = result.jobs[0];
  const bodyshop = job?.bodyshop;

  if (!bodyshop) {
    return handlePaymentValidationError(
      res,
      logger,
      "intellipay-postback-bodyshop-not-found",
      "Bodyshop not found",
      logMeta
    );
  }

  const ipMapping = bodyshop.intellipay_config?.payment_map;

  logger.log("intellipay-postback-invoice-job-fetched", "DEBUG", "api", null, {
    job,
    ...logMeta
  });

  // Create payment record
  const paymentResult = await gqlClient.request(INSERT_NEW_PAYMENT, {
    paymentInput: {
      amount: values.total,
      transactionid: values.authcode,
      payer: "Customer",
      type: getPaymentType(ipMapping, values.cardtype),
      jobid: job.id,
      date: moment()
        .tz(bodyshop?.timezone ?? "UTC")
        .format("YYYY-MM-DD")
    }
  });

  logger.log("intellipay-postback-invoice-payment-success", "DEBUG", "api", null, {
    paymentResult,
    ...logMeta
  });

  // Create payment response record
  const responseResults = await gqlClient
    .request(INSERT_PAYMENT_RESPONSE, {
      paymentResponse: {
        amount: values.total,
        bodyshopid: bodyshop.id,
        paymentid: paymentResult.insert_payments.returning[0].id,
        jobid: job.id,
        declinereason: "Approved",
        ext_paymentid: values.paymentid,
        successful: true,
        response: values
      }
    })
    .catch((err) => {
      logger.log("intellipay-postback-invoice-response-error", "ERROR", "api", null, {
        err,
        ...logMeta
      });
    });

  logger.log("intellipay-postback-invoice-response-success", "DEBUG", "api", null, {
    responseResults,
    ...logMeta
  });

  return res.sendStatus(200);
};

module.exports = handleInvoiceBasedPayment;
