const queries = require("../graphql-client/queries");
const logger = require("../utils/logger");
const { CalculateExpectedHoursForJob, RoundPayrollHours } = require("./pay-all");
const moment = require("moment");

const normalizePercent = (value) => Math.round((Number(value || 0) + Number.EPSILON) * 10000) / 10000;

const getTaskPresetAllocationError = (taskPresets = []) => {
  const totalsByLaborType = {};

  taskPresets.forEach((taskPreset) => {
    const percent = normalizePercent(taskPreset?.percent);

    if (!percent) {
      return;
    }

    const laborTypes = Array.isArray(taskPreset?.hourstype) ? taskPreset.hourstype : [];

    laborTypes.forEach((laborType) => {
      if (!laborType) {
        return;
      }

      totalsByLaborType[laborType] = normalizePercent((totalsByLaborType[laborType] || 0) + percent);
    });
  });

  const overAllocatedType = Object.entries(totalsByLaborType).find(([, total]) => total > 100);

  if (!overAllocatedType) {
    return null;
  }

  const [laborType, total] = overAllocatedType;
  return `Task preset percentages for labor type ${laborType} total ${total}% and cannot exceed 100%.`;
};

exports.GetTaskPresetAllocationError = getTaskPresetAllocationError;

exports.claimtask = async function (req, res) {
  const { jobid, task, calculateOnly, employee } = req.body;
  logger.log("job-payroll-pay-all", "DEBUG", req.user.email, jobid, null);

  const BearerToken = req.BearerToken;
  const client = req.userGraphQLClient;

  try {
    const { jobs_by_pk: job } = await client
      .setHeaders({ Authorization: BearerToken })
      .request(queries.QUERY_JOB_PAYROLL_DATA, {
        id: jobid
      });

    const taskPresets = job.bodyshop?.md_tasks_presets?.presets || [];
    const taskPresetAllocationError = getTaskPresetAllocationError(taskPresets);
    if (taskPresetAllocationError) {
      res.status(400).json({ success: false, error: taskPresetAllocationError });
      return;
    }

    const theTaskPreset = taskPresets.find((tp) => tp.name === task);
    if (!theTaskPreset) {
      res.status(400).json({ success: false, error: "Provided task preset not found." });
      return;
    }

    const taskAlreadyCompleted = (job.completed_tasks || []).some((completedTask) => completedTask?.name === task);
    if (taskAlreadyCompleted) {
      res.status(400).json({ success: false, error: "Provided task preset has already been completed for this job." });
      return;
    }

    //Get all of the assignments that are filtered.
    const { assignmentHash, employeeHash } = CalculateExpectedHoursForJob(job, theTaskPreset.hourstype);
    const ticketsToInsert = [];
    //Then add them in based on a percentage to each employee.

    Object.keys(employeeHash).forEach((employeeIdKey) => {
      //At the employee level.
      Object.keys(employeeHash[employeeIdKey]).forEach((laborTypeKey) => {
        const expected = employeeHash[employeeIdKey][laborTypeKey];
        const expectedHours = RoundPayrollHours(expected.hours * (theTaskPreset.percent / 100));

        ticketsToInsert.push({
          task_name: task,
          jobid: job.id,
          bodyshopid: job.bodyshop.id,
          employeeid: employeeIdKey,
          productivehrs: expectedHours,
          rate: expected.rate,
          ciecacode: laborTypeKey,
          flat_rate: true,
          created_by: employee?.name || req.user.email,
          payout_context: {
            ...(expected.payoutContext || {}),
            generated_by: req.user.email,
            generated_at: new Date().toISOString(),
            generated_from: "claimtask",
            task_name: task
          },
          cost_center: job.bodyshop.md_responsibility_centers.defaults.costs[laborTypeKey],
          memo: `*Flagged Task* ${theTaskPreset.memo}`
        });
      });
    });
    if (!calculateOnly) {
      //Insert the time ticekts if we're not just calculating them.
      await client.request(queries.INSERT_TIME_TICKETS, {
        timetickets: ticketsToInsert.filter((ticket) => ticket.productivehrs !== 0)
      });
      await client.request(queries.UPDATE_JOB, {
        jobId: job.id,
        job: {
          status: theTaskPreset.nextstatus,
          completed_tasks: [
            ...job.completed_tasks,
            {
              name: task,
              completedat: moment(),
              completed_by: employee,
              useremail: req.user.email
            }
          ]
        }
      });
    }
    res.json({ unassignedHours: assignmentHash.unassigned, ticketsToInsert });
  } catch (error) {
    logger.log("job-payroll-claim-task-error", "ERROR", req.user.email, jobid, {
      jobid: jobid,
      error
    });
    res.status(400).json({ success: false, error: error.message });
  }
};
