import gql from "graphql-tag";
import _ from "lodash";
import client from "../graphql/GraphQLClient";
import {
  INSERT_NEW_JOB,
  QUERY_JOB_BY_CLM_NO,
  UPDATE_JOB,
} from "../graphql/jobs.queries";
import { QUERY_GROUPS_BY_MAKE_TYPE } from "../graphql/veh_group.queries";
import { store } from "../redux/store";
import moment from "moment";
const { logger } = window;

export async function UpsertEstimate(job) {
  const shopId = store.getState().user.bodyshop.id;
  logger.info("Beginning Upserting job from Renderer.");
  const parsedYr = parseInt(job.v_model_yr);
  console.log("UpsertEstimate -> parsedYr", parsedYr);

  logger.info(
    moment(job.loss_date).year() -
      (parsedYr >= 0 ? 2000 + parsedYr : 1900 + parsedYr)
  );

  job = {
    ...job,
    group: await DetermineVehicleGroup(job),
    v_age:
      moment(job.loss_date).year() -
      (parsedYr >= 0 ? 2000 + parsedYr : 1900 + parsedYr),
  };

  const existingJobs = await client.query({
    query: QUERY_JOB_BY_CLM_NO,
    variables: { clm_no: job.clm_no },
  });

  if (existingJobs.data.jobs.length === 1) {
    let suppDelta = await GetSupplementDelta(
      existingJobs.data.jobs[0].id,
      existingJobs.data.jobs[0].joblines,
      job.joblines.data
    );

    logger.info("Attemping to update job record.");
    await client.mutate({
      mutation: gql`
        ${suppDelta}
      `,
    });
    delete job.joblines;

    const updatedJob = await client.mutate({
      mutation: UPDATE_JOB,
      variables: { jobId: existingJobs.data.jobs[0].id, job: job },
    });
    logger.info("Job updated succesfully.");

    console.log("UpsertEstimate -> updatedJob", updatedJob);
  } else {
    logger.info("Attemping to insert job record.");

    const result = await client.mutate({
      mutation: INSERT_NEW_JOB,
      variables: {
        job: { ...job, bodyshopid: shopId },
      },
      refetchQueries: ["QUERY_ALL_JOBS_PAGINATED"],
    });
    logger.info("Job inserted succesfully.");

    console.log("UpsertEstimate -> result", result);
  }
}

export const GetSupplementDelta = async (jobId, existingLinesO, newLines) => {
  const existingLines = _.cloneDeep(existingLinesO);

  console.log("GetSupplementDelta -> newLines", newLines);
  console.log("GetSupplementDelta -> existingLines", existingLines);
  const linesToInsert = [];
  const linesToUpdate = [];

  newLines.forEach((newLine) => {
    const matchingIndex = existingLines.findIndex(
      (eL) => eL.unq_seq === newLine.unq_seq
    );
    if (matchingIndex >= 0) {
      //Found a relevant matching line. Add it to lines to update.
      linesToUpdate.push({
        id: existingLines[matchingIndex].id,
        newData: newLine,
      });
      //Splice out item we found for performance.
      existingLines.splice(matchingIndex, 1);
    } else {
      //Didn't find a match. Must be a new line.
      linesToInsert.push(newLine);
    }
  });

  //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.reduce((acc, value, idx) => {
    return acc + generateRemoveQuery(value, idx);
  }, "");

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

const generateInsertQuery = (lineToInsert, index, jobId) => {
  lineToInsert.jobid = jobId;
  return `
  insert_joblines${index}: insert_joblines(objects: ${JSON.stringify(
    lineToInsert
  ).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 `
 delete_joblines_r${index}: delete_joblines_by_pk(id: "${lineToRemove.id}") {
      id
  }`;
};

const DetermineVehicleGroup = async (job) => {
  logger.info(
    "Searching for vehicle groups.!",
    job.v_makedesc.toUpperCase(),
    job.v_type ? job.v_type.toUpperCase() : null
  );

  const vehicleGroups = await client.query({
    query: QUERY_GROUPS_BY_MAKE_TYPE,
    variables: {
      make: job.v_makedesc.toUpperCase(),
      type: job.v_type ? job.v_type.toUpperCase() : null,
    },
  });

  if (vehicleGroups.data.veh_groups.length === 1) {
    logger.info("Found 1 vehicle group.!", vehicleGroups.data.veh_groups[0]);
    return vehicleGroups.data.veh_groups[0].group;
  } else if (vehicleGroups.data.veh_groups.length === 0) {
    //Uh-oh, should only be 1.
    logger.info("No vehicle groups found.");
    return null;
  } else {
    //Should never be here.
    alert("Fatal error. Multiple vehicle groups found for this claim.");
    logger.error(
      "Found multiple vehicle groups!",
      job.v_makedesc.toUpperCase(),
      job.v_type ? job.v_type.toUpperCase() : null
    );
  }

  return "";
};
