/**
 * @fileoverview Notification event handlers.
 * This module exports functions to handle various notification events.
 * Each handler optionally calls the scenarioParser and logs errors if they occur,
 * then returns a JSON response with a success message.
 */

const scenarioParser = require("./scenarioParser");
const { autoAddWatchers } = require("./autoAddWatchers"); // New module

/**
 * Processes a notification event by invoking the scenario parser.
 * The scenarioParser is intentionally not awaited so that the response is sent immediately.
 *
 * @param {Object} req - Express request object.
 * @param {Object} res - Express response object.
 * @param {string} parserPath - The key path to be passed to scenarioParser.
 * @param {string} successMessage - The message to return on success.
 * @returns {Promise<Object>} A promise that resolves to an Express JSON response.
 */
async function processNotificationEvent(req, res, parserPath, successMessage) {
  const { logger } = req;

  // Call scenarioParser but don't await it; log any error that occurs.
  scenarioParser(req, parserPath).catch((error) => {
    logger.log("notifications-error", "error", "notifications", null, { message: error?.message, stack: error?.stack });
  });

  return res.status(200).json({ message: successMessage });
}

/**
 * Handle job change notifications.
 *
 * @param {Object} req - Express request object.
 * @param {Object} res - Express response object.
 * @returns {Promise<Object>} JSON response with a success message.
 */
const handleJobsChange = async (req, res) =>
  processNotificationEvent(req, res, "req.body.event.new.id", "Job Notifications Event Handled.");

/**
 * Handle bills change notifications.
 *
 * @param {Object} req - Express request object.
 * @param {Object} res - Express response object.
 * @returns {Promise<Object>} JSON response with a success message.
 */
const handleBillsChange = async (req, res) =>
  processNotificationEvent(req, res, "req.body.event.new.jobid", "Bills Changed Notification Event Handled.");

/**
 * Handle documents change notifications.
 * Processes both old and new job IDs if the document was moved between jobs.
 *
 * @param {Object} req - Express request object.
 * @param {Object} res - Express response object.
 * @returns {Promise<Object>} JSON response with a success message.
 */
const handleDocumentsChange = async (req, res) => {
  const { logger } = req;
  const newJobId = req.body?.event?.data?.new?.jobid;
  const oldJobId = req.body?.event?.data?.old?.jobid;

  // If jobid changed (document moved between jobs), we need to notify both jobs
  if (oldJobId && newJobId && oldJobId !== newJobId) {
    // Process notification for new job ID
    scenarioParser(req, "req.body.event.new.jobid").catch((error) => {
      logger.log("notifications-error", "error", "notifications", null, {
        message: error?.message,
        stack: error?.stack
      });
    });

    // Create a modified request for old job ID
    const oldJobReq = {
      body: {
        ...req.body,
        event: {
          ...req.body.event,
          data: {
            new: {
              ...req.body.event.data.old,
              // Add a flag to indicate this document was moved away
              _documentMoved: true,
              _movedToJob: newJobId
            },
            old: null
          }
        }
      },
      logger,
      sessionUtils: req.sessionUtils
    };

    // Process notification for old job ID using the modified request
    scenarioParser(oldJobReq, "req.body.event.new.jobid").catch((error) => {
      logger.log("notifications-error", "error", "notifications", null, {
        message: error?.message,
        stack: error?.stack
      });
    });

    return res.status(200).json({ message: "Documents Change Notifications Event Handled for both jobs." });
  }

  // Otherwise just process the new job ID
  scenarioParser(req, "req.body.event.new.jobid").catch((error) => {
    logger.log("notifications-error", "error", "notifications", null, {
      message: error?.message,
      stack: error?.stack
    });
  });

  return res.status(200).json({ message: "Documents Change Notifications Event Handled." });
};

/**
 * Handle job lines change notifications.
 *
 * @param {Object} req - Express request object.
 * @param {Object} res - Express response object.
 * @returns {Promise<Object>} JSON response with a success message.
 */
const handleJobLinesChange = async (req, res) =>
  processNotificationEvent(req, res, "req.body.event.new.jobid", "JobLines Change Notifications Event Handled.");

/**
 * Handle notes change notifications.
 *
 * @param {Object} req - Express request object.
 * @param {Object} res - Express response object.
 * @returns {Promise<Object>} JSON response with a success message.
 */
const handleNotesChange = async (req, res) =>
  processNotificationEvent(req, res, "req.body.event.new.jobid", "Notes Changed Notification Event Handled.");

/**
 * Handle payments change notifications.
 *
 * @param {Object} req - Express request object.
 * @param {Object} res - Express response object.
 * @returns {Promise<Object>} JSON response with a success message.
 */
const handlePaymentsChange = async (req, res) =>
  processNotificationEvent(req, res, "req.body.event.new.jobid", "Payments Changed Notification Event Handled.");

/**
 * Handle task socket emit.
 * @param req
 */
const handleTaskSocketEmit = (req) => {
  const {
    logger,
    ioRedis,
    ioHelpers: { getBodyshopRoom }
  } = req;
  const event = req.body.event;
  const op = event.op;
  let taskData;
  let type;
  let bodyshopId;

  if (op === "INSERT") {
    taskData = event.data.new;
    if (taskData.deleted) {
      logger.log("tasks-event-insert-deleted", "warn", "notifications", null, { id: taskData.id });
    } else {
      type = "task-created";
      bodyshopId = taskData.bodyshopid;
    }
  } else if (op === "UPDATE") {
    const newData = event.data.new;
    const oldData = event.data.old;
    taskData = newData;
    bodyshopId = newData.bodyshopid;

    if (newData.deleted && !oldData.deleted) {
      type = "task-deleted";
      taskData = { id: newData.id, assigned_to: newData.assigned_to };
    } else if (!newData.deleted && oldData.deleted) {
      type = "task-created";
    } else if (!newData.deleted) {
      type = "task-updated";
    }
  } else {
    logger.log("tasks-event-unknown-op", "warn", "notifications", null, { op });
  }

  if (bodyshopId && ioRedis && type) {
    const room = getBodyshopRoom(bodyshopId);
    ioRedis.to(room).emit("bodyshop-message", { type, payload: taskData });
    logger.log("tasks-event-emitted", "info", "notifications", null, { type, bodyshopId });
  } else if (type) {
    logger.log("tasks-event-missing-data", "error", "notifications", null, { bodyshopId, hasIo: !!ioRedis, type });
  }
};

/**
 * Handle tasks change notifications.
 * Note: this also handles task center notifications.
 *
 * @param {Object} req - Express request object.
 * @param {Object} res - Express response object.
 * @returns {Promise<Object>} JSON response with a success message.
 */
const handleTasksChange = async (req, res) => {
  handleTaskSocketEmit(req);
  return processNotificationEvent(req, res, "req.body.event.new.jobid", "Tasks Notifications Event Handled.");
};

/**
 * Handle time tickets change notifications.
 *
 * @param {Object} req - Express request object.
 * @param {Object} res - Express response object.
 * @returns {Promise<Object>} JSON response with a success message.
 */
const handleTimeTicketsChange = async (req, res) =>
  processNotificationEvent(req, res, "req.body.event.new.jobid", "Time Tickets Changed Notification Event Handled.");

/**
 * Handle parts dispatch change notifications.
 * Note: Placeholder
 *
 * @param {Object} req - Express request object.
 * @param {Object} res - Express response object.
 * @returns {Object} JSON response with a success message.
 *
 */
const handlePartsDispatchChange = (req, res) => res.status(200).json({ message: "Parts Dispatch change handled." });

/**
 * Handle parts order change notifications.
 * Note: Placeholder
 *
 * @param {Object} req - Express request object.
 * @param {Object} res - Express response object.
 * @returns {Object} JSON response with a success message.
 */
const handlePartsOrderChange = (req, res) => res.status(200).json({ message: "Parts Order change handled." });

/**
 * Handle auto-add watchers for new jobs.
 *
 * @param {Object} req - Express request object.
 * @param {Object} res - Express response object.
 * @returns {Promise<Object>} JSON response with a success message.
 */
const handleAutoAddWatchers = async (req, res) => {
  const { logger } = req;

  // Call autoAddWatchers but don't await it; log any error that occurs.
  autoAddWatchers(req).catch((error) => {
    logger.log("auto-add-watchers-error", "error", "notifications", null, {
      message: error?.message,
      stack: error?.stack
    });
  });

  return res.status(200).json({ message: "Auto-Add Watchers Event Handled." });
};

module.exports = {
  handleJobsChange,
  handleBillsChange,
  handleDocumentsChange,
  handleJobLinesChange,
  handleNotesChange,
  handlePartsDispatchChange,
  handlePartsOrderChange,
  handlePaymentsChange,
  handleTasksChange,
  handleTimeTicketsChange,
  handleAutoAddWatchers
};
