import { gql } from "@apollo/client";
import _ from "lodash";
import { GET_ALL_JOBLINES_BY_PK } from "../../graphql/jobs-lines.queries";

export const GetSupplementDelta = async (client, jobId, newLines) => {
  const {
    data: { joblines: existingLinesFromDb }
  } = await client.query({
    query: GET_ALL_JOBLINES_BY_PK,
    variables: { id: jobId }
  });

  const existingLines = _.cloneDeep(existingLinesFromDb);
  const linesToInsert = [];
  const linesToUpdate = [];

  newLines.forEach((newLine) => {
    const matchingIndexLines = [];
    existingLines.forEach((eL, index) => {
      if (eL.unq_seq === newLine.unq_seq) {
        matchingIndexLines.push({ index, record: eL });
      }
    });

    if (matchingIndexLines.length === 0) {
      //Didn't find a match. Must be a new line.
      linesToInsert.push(newLine);
    }
    //If we find only 1, we can use the old logic.
    else if (matchingIndexLines.length === 1) {
      //Found a relevant matching line. Add it to lines to update.
      linesToUpdate.push({
        id: matchingIndexLines[0].record.id,
        newData: { ...newLine, removed: false, act_price_before_ppc: null }
      });
      //Splice out item we found for performance.
      existingLines.splice(matchingIndexLines[0].index, 1);
    } else if (matchingIndexLines.length === 2) {
      //if we find 2, we need to separate it out by the non-refinish lines and splice one out.
      //Find the mathcing one depending on whether this is the refiniish one or not.
      const matchingLine = matchingIndexLines.find((i) =>
        newLine.mod_lbr_ty === "LAR" ? i.record.mod_lbr_ty === "LAR" : i.record.mod_lbr_ty !== "LAR"
      );

      linesToUpdate.push({
        id: matchingLine.record.id,
        newData: { ...newLine, removed: false, act_price_before_ppc: null }
      });
      //Splice out item we found for performance.
      existingLines.splice(matchingLine.index, 1);
    } else {
      //We found more than 2 matching lines. We should never get here. Throw a warning and back out!
      throw new Error("Too many matching lines found. Ensure EMS file is valid.");
    }
  });

  //Wahtever is left in the existing lines, are lines that should be removed.
  const insertQueries = linesToInsert.reduce((acc, value, idx) => {
    return acc + generateInsertQuery(value, idx, jobId);
  }, "");

  const updateQueries = linesToUpdate.reduce((acc, value, idx) => {
    return acc + generateUpdateQuery(value, idx);
  }, "");

  const removeQueries = existingLines
    .filter((l) => !l.manual_line)
    .reduce((acc, value, idx) => {
      return acc + generateRemoveQuery(value, idx);
    }, "");
  //console.log(insertQueries, updateQueries, removeQueries);

  if ((insertQueries + updateQueries + removeQueries).trim() === "") {
    return new Promise((resolve) => {
      resolve(null);
    });
  }

  return new Promise((resolve) => {
    resolve(gql`
      mutation SUPPLEMENT_EST_LINES{
        ${insertQueries + updateQueries + removeQueries}
      }
    `);
  });
};

const generateInsertQuery = (lineToInsert, index, jobId) => {
  return `
  insert_joblines${index}: insert_joblines(objects: ${JSON.stringify({
    ...lineToInsert,
    jobid: jobId
  }).replace(/"(\w+)"\s*:/g, "$1:")}) {
      returning {
        id
      }
    }`;
};

const generateUpdateQuery = (lineToUpdate, index) => {
  return `
  update_joblines${index}: update_joblines(where: { id: { _eq: "${
    lineToUpdate.id
  }" } }, _set: ${JSON.stringify(lineToUpdate.newData).replace(/"(\w+)"\s*:/g, "$1:")}) {
    returning {
      id
    }
  }`;
};

const generateRemoveQuery = (lineToRemove, index) => {
  return `
  update_joblines_r${index}: update_joblines(where: {id: {_eq: "${lineToRemove.id}"}}, _set: {removed: true}) {
    returning{
      id
    }
  }`;
};
