const _ = require("lodash");
const queries = require("../graphql-client/queries");
const moment = require("moment");
const durationToHumanReadable = require("../utils/durationToHumanReadable");
const calculateStatusDuration = require("../utils/calculateStatusDuration");
const getLifecycleStatusColor = require("../utils/getLifecycleStatusColor");

const jobLifecycle = async (req, res) => {
  // Grab the jobids and statuses from the request body
  const { jobids, statuses } = req.body;
  const { logger } = req;

  if (!jobids) {
    return res.status(400).json({
      error: "Missing jobids"
    });
  }

  const jobIDs = _.isArray(jobids) ? jobids : [jobids];

  logger.log("job-lifecycle-start", "DEBUG", req?.user?.email, null, {
    jobids: jobIDs
  });

  try {
    const client = req.userGraphQLClient;
    const resp = await client.request(queries.QUERY_TRANSITIONS_BY_JOBID, { jobids: jobIDs });

    const transitions = resp.transitions;

    if (!transitions) {
      return res.status(200).json({
        jobIDs,
        transitions: []
      });
    }

    const transitionsByJobId = _.groupBy(resp.transitions, "jobid");

    const groupedTransitions = {};
    const allDurations = [];

    for (let jobId in transitionsByJobId) {
      let lifecycle = transitionsByJobId[jobId].map((transition) => {
        transition.start_readable = transition.start ? moment(transition.start).fromNow() : "N/A";
        transition.end_readable = transition.end ? moment(transition.end).fromNow() : "N/A";

        if (transition.duration) {
          transition.duration_seconds = Math.round(transition.duration / 1000);
          transition.duration_minutes = Math.round(transition.duration_seconds / 60);
          let duration = moment.duration(transition.duration);
          transition.duration_readable = durationToHumanReadable(duration);
        } else {
          transition.duration_seconds = 0;
          transition.duration_minutes = 0;
          transition.duration_readable = "N/A";
        }
        return transition;
      });

      const durations = calculateStatusDuration(lifecycle, statuses);

      groupedTransitions[jobId] = {
        lifecycle,
        durations
      };

      if (durations?.summations) {
        allDurations.push(durations.summations);
      }
    }

    const finalSummations = [];
    const flatGroupedAllDurations = _.groupBy(allDurations.flat(), "status");

    const finalStatusCounts = Object.keys(flatGroupedAllDurations).reduce((acc, status) => {
      acc[status] = flatGroupedAllDurations[status].length;
      return acc;
    }, {});
    // Calculate total value of all statuses
    const finalTotal = Object.values(flatGroupedAllDurations).reduce((total, statusArr) => {
      return total + statusArr.reduce((acc, curr) => acc + curr.value, 0);
    }, 0);
 
    Object.keys(flatGroupedAllDurations).forEach((status) => {
      const value = flatGroupedAllDurations[status].reduce((acc, curr) => acc + curr.value, 0);
      const humanReadable = durationToHumanReadable(moment.duration(value));
      const percentage = finalTotal > 0 ? (value / finalTotal) * 100 : 0;
      const color = getLifecycleStatusColor(status);
      const roundedPercentage = `${Math.round(percentage)}%`;
      const averageValue = _.size(jobIDs) > 0 ? value / jobIDs.length : 0;
      const averageHumanReadable = durationToHumanReadable(moment.duration(averageValue));
      finalSummations.push({
        status,
        value,
        humanReadable,
        percentage,
        color,
        roundedPercentage,
        averageValue,
        averageHumanReadable
      });
    });

    return res.status(200).json({
      jobIDs,
      transition: groupedTransitions,
      durations: {
        jobs: jobIDs.length,
        summations: finalSummations,
        totalStatuses: finalSummations.length,
        total: finalTotal,
        statusCounts: finalStatusCounts,
        humanReadable: durationToHumanReadable(moment.duration(finalTotal)),
        averageValue: _.size(jobIDs) > 0 ? finalTotal / jobIDs.length : 0,
        averageHumanReadable:
          _.size(jobIDs) > 0
            ? durationToHumanReadable(moment.duration(finalTotal / jobIDs.length))
            : durationToHumanReadable(moment.duration(0))
      }
    });
  } catch (error) {
    logger.log("job-lifecycle-error", "ERROR", req?.user?.email, null, {
      jobids: jobIDs,
      statuses: statuses ? JSON.stringify(statuses) : "N/A",
      error: error.message
    });
    return res.status(500).json({
      error: "Internal server error"
    });
  }
};

module.exports = jobLifecycle;
