const path = require("path");
const fs = require("fs");
const Dinero = require("dinero.js");
const { gql } = require("graphql-request");
const AxiosLib = require("axios").default;
const axios = AxiosLib.create();
const pLimit = require("p-limit");
const converter = require("json-2-csv");

Dinero.globalRoundingMode = "HALF_EVEN";
const client = require("./server/graphql-client/graphql-client").client;
require("dotenv").config({
  path: path.resolve(process.cwd(), `.env.${process.env.NODE_ENV || "development"}`)
});

async function RunTheTest() {
  const bodyshopids = ["71f8494c-89f0-43e0-8eb2-820b52d723bc"];
  const bearerToken = `Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6ImI4Y2FjOTViNGE1YWNkZTBiOTY1NzJkZWU4YzhjOTVlZWU0OGNjY2QiLCJ0eXAiOiJKV1QifQ.eyJuYW1lIjoiUGF0cmljayBGaWMgKERFVikiLCJodHRwczovL2hhc3VyYS5pby9qd3QvY2xhaW1zIjp7IngtaGFzdXJhLWRlZmF1bHQtcm9sZSI6InVzZXIiLCJ4LWhhc3VyYS1hbGxvd2VkLXJvbGVzIjpbInVzZXIiXSwieC1oYXN1cmEtdXNlci1pZCI6ImhOSjhBRHB0REhRQkRFcXNCOFFNWVRqaURuZjEifSwiaXNzIjoiaHR0cHM6Ly9zZWN1cmV0b2tlbi5nb29nbGUuY29tL2ltZXgtZGV2IiwiYXVkIjoiaW1leC1kZXYiLCJhdXRoX3RpbWUiOjE3MzAxMzIwMjksInVzZXJfaWQiOiJoTko4QURwdERIUUJERXFzQjhRTVlUamlEbmYxIiwic3ViIjoiaE5KOEFEcHRESFFCREVxc0I4UU1ZVGppRG5mMSIsImlhdCI6MTczMDg0MTc2NSwiZXhwIjoxNzMwODQ1MzY1LCJlbWFpbCI6InBhdHJpY2tAaW1leC5kZXYiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsImZpcmViYXNlIjp7ImlkZW50aXRpZXMiOnsiZW1haWwiOlsicGF0cmlja0BpbWV4LmRldiJdfSwic2lnbl9pbl9wcm92aWRlciI6InBhc3N3b3JkIn19.npQWkyB5cB4wmkaBsQiY3JbvBM9vKPqf3e22nVHnSydGcQi0p9M2mca9FcDtdcWvQlShUM63FF-6KkzpovC92sHauNmzCSXRInaaCPEussUUNSJEe2gEV03tYX447LkkSmFQbJ5V6qLTIDelm25fF0MoEDVnLTgythK_9927f8cxKZH1kEow0ymDeMaWey1sRyu7n15OJMcu692mfuQnBAArGTHGJ4YmReI7tMmdrV438MLxuVpH5CLb6uzlUdZoJ__7yh0kz0lkZEeHQAL8yq-0fISbPeZ5uXuMzYGrHuuKsIPRoeShVSVnF7ov8yTT3_YrCkhYbxl0eSTfBB5OdQ`;

  const { jobs } = await client.request(
    gql`
      query GET_JOBS($bodyshopids: [uuid!]!) {
        jobs(where: { shopid: { _in: $bodyshopids } }, order_by: { created_at: desc }) {
          id
          ro_number
          job_totals
          cieca_ttl
        }
      }
    `,
    {
      bodyshopids
    }
  );

  const results = [];

  const limit = pLimit(5); // Set concurrency limit to 3

  const tasks = jobs.map((job, index) => {
    return limit(async () => {
      process.stdout.cursorTo(0);
      process.stdout.write(
        `Processing job ${index + 1} of ${jobs.length}. Failed jobs: ${results.filter((r) => r.overallTotalCorrect !== "PASS").length}. Correct jobs because of adjustment: ${results.filter((r) => r.correctJobsBecauseOfAdjustment).length}`
      );

      try {
        await axios.post(
          `http://localhost:4000/job/totalsssu`,
          { id: job.id },
          { headers: { Authorization: bearerToken } }
        );
        const { jobs_by_pk: newjob } = await client.request(
          gql`
            query GET_JOBS($id: uuid!) {
              jobs_by_pk(id: $id) {
                id
                ro_number
                cieca_ttl
                job_totals
                ownr_fn
                ownr_ln
                ownr_co_nm
                ins_co_nm
                comment
              }
            }
          `,
          {
            id: job.id
          }
        );

        const result = {
          id: newjob.id,
          owner: `${newjob.ownr_fn} ${newjob.ownr_ln} ${job.ownr_co_nm || ""}`,
          ins_co: newjob.ins_co_nm,
          comment: newjob.comment,
          imexsubtotal: Dinero(newjob.job_totals.totals.subtotal).toFormat("0.00"),
          imextotalrepair: Dinero(newjob.job_totals.totals.total_repairs).toFormat("0.00"),
          g_tax: newjob.cieca_ttl.data.g_tax,
          n_ttl_amt: newjob.cieca_ttl.data.n_ttl_amt,
          g_ttl_amt: newjob.cieca_ttl.data.g_ttl_amt
        };

        const calcTotal = newjob.job_totals.totals.total_repairs.amount;
        const ttlTotal = newjob.cieca_ttl.data.g_ttl_amt * 100;
        result.difference = (calcTotal - ttlTotal) / 100;

        if (Math.abs(calcTotal - ttlTotal) > 3) {
          result.overallTotalCorrect = "***FAIL***";
        } else {
          result.overallTotalCorrect = "PASS";
        }
        result.ttl_adjustment = Dinero(newjob.job_totals.totals.ttl_adjustment).toFormat();
        result.ttl_tax_adjustment = Dinero(newjob.job_totals.totals.ttl_tax_adjustment).toFormat();

        const calcTaxDinero = Dinero(newjob.job_totals.totals.us_sales_tax_breakdown.ty1Tax)
          .add(Dinero(newjob.job_totals.totals.us_sales_tax_breakdown.ty2Tax))
          .add(Dinero(newjob.job_totals.totals.us_sales_tax_breakdown.ty3Tax))
          .add(Dinero(newjob.job_totals.totals.us_sales_tax_breakdown.ty4Tax))
          .add(Dinero(newjob.job_totals.totals.us_sales_tax_breakdown.ty5Tax))
          .add(Dinero(newjob.job_totals.totals.ttl_tax_adjustment));
        result.calcTax = calcTaxDinero.toFormat("0.00");
        const calcTax = calcTaxDinero.getAmount() / 100;
        const emsTax = newjob.cieca_ttl.data.g_tax;
        result.taxDifference = calcTax - emsTax;

        if (Math.abs(calcTax - emsTax) > 3) {
          result.taxCorrect = "***FAIL***";
        } else {
          result.taxCorrect = "PASS";
        }

        results.push(result);
      } catch (error) {
        results.push({
          ro_number: job.ro_number,
          id: job.id,
          result: error.message
        });
      }
    });
  });

  await Promise.all(tasks);

  console.table(results.filter((r) => r.overallTotalCorrect !== "PASS"));
  console.log("=======================================");
  const summary = results.reduce(
    (acc, val) => {
      if (val.result === "PASS") {
        return { ...acc, pass: acc.pass + 1 };
      } else {
        return { ...acc, fail: acc.fail + 1 };
      }
    },
    { pass: 0, fail: 0 }
  );
  console.log("Pass Rate: ", ((summary.pass / (summary.fail + summary.pass)) * 100).toFixed(1));

  const ret = converter.json2csv(results, { emptyFieldValue: "" });

  fs.writeFile(`./logs/totalstest-${Date.now()}.csv`, ret, (error) => console.log(error));
}

RunTheTest().catch((error) => {
  console.log("Error in RunTheTest: ", error);
});
