const InstanceManager = require("../utils/instanceMgr").default;
const logger = require("../utils/logger");
const client = require("../graphql-client/graphql-client").client;
const queries = require("../graphql-client/queries");
const generateEmailTemplate = require("./generateTemplate");
const moment = require("moment-timezone");
const { taskEmailQueue } = require("./tasksEmailsQueue");
const mailer = require("./mailer");
const { InstanceEndpoints } = require("../utils/instanceMgr");
const { formatTaskPriority } = require("../notifications/stringHelpers");

// Initialize the Tasks Email Queue
const tasksEmailQueue = taskEmailQueue();

// Cleanup function for the Tasks Email Queue
// eslint-disable-next-line no-unused-vars
const tasksEmailQueueCleanup = async () => {
  try {
    // Example async operation
    // console.log("Performing Tasks Email Reminder process cleanup...");
    await new Promise((resolve) => tasksEmailQueue.destroy(() => resolve()));
    // eslint-disable-next-line no-unused-vars
  } catch (err) {
    // console.error("Tasks Email Reminder process cleanup failed:", err);
  }
};

// if (process.env.NODE_ENV !== "development") {
//   // Handling SIGINT (e.g., Ctrl+C)
//   process.on("SIGINT", async () => {
//     console.log("Handling SIGNIT For Tasks Cleanup");
//     await tasksEmailQueueCleanup();
//     process.exit(0);
//   });
//   // Handling SIGTERM (e.g., sent by system shutdown)
//   process.on("SIGTERM", async () => {
//     console.log("Handling SIGTERM For Tasks Cleanup");
//     await tasksEmailQueueCleanup();
//     process.exit(0);
//   });
//   // Handling uncaught exceptions
//   process.on("uncaughtException", async (err) => {
//     console.log("Handling uncaughtException For Tasks Cleanup");
//     await tasksEmailQueueCleanup();
//     process.exit(1);
//   });
//   // Handling unhandled promise rejections
//   process.on("unhandledRejection", async (reason, promise) => {
//     console.log("Handling unhandledRejection For Tasks Cleanup");
//     await tasksEmailQueueCleanup();
//     process.exit(1);
//   });
// }

/**
 * Format the date for the email.
 * @param date
 * @returns {string|string}
 */
const formatDate = (date) => {
  return date ? `| Due on: ${moment(date).format("MM/DD/YYYY")}` : "";
};

/**
 * Generate the email template arguments.
 * @param title
 * @param priority
 * @param description
 * @param dueDate
 * @param createdBy
 * @param bodyshop
 * @param job
 * @param taskId
 * @returns {{header, body: string, subHeader: string}}
 */
const generateTemplateArgs = (title, priority, description, dueDate, bodyshop, job, taskId, dateLine, createdBy) => {
  const endPoints = InstanceEndpoints();
  return {
    header: title,
    subHeader: `Body Shop: ${bodyshop.shopname} | Priority: ${formatTaskPriority(priority)} ${formatDate(dueDate)} | Created By: ${createdBy || "N/A"}`,
    body: `Reference: ${job.ro_number || "N/A"} | ${job.ownr_co_nm ? job.ownr_co_nm : `${job.ownr_fn || ""} ${job.ownr_ln || ""}`.trim()} | ${`${job.v_model_yr || ""} ${job.v_make_desc || ""} ${job.v_model_desc || ""}`.trim()}<br>${description ? description.concat("<br>") : ""}<a href="${endPoints}/manage/tasks/alltasks?taskid=${taskId}">View this task.</a>`,
    dateLine
  };
};

/**
 * Send the email.
 * @param type
 * @param to
 * @param subject
 * @param html
 * @param taskIds
 * @param successCallback
 */
const sendMail = (type, to, subject, html, taskIds, successCallback) => {
  const fromEmails = InstanceManager({
    imex: "ImEX Online <noreply@imex.online>",
    rome: "Rome Online <noreply@romeonline.io>"
  });

  mailer.sendMail(
    {
      from: fromEmails,
      to,
      subject,
      html
    },
    (error, info) => {
      if (info) {
        if (typeof successCallback === "function" && taskIds && taskIds.length) {
          successCallback(taskIds);
        }
      } else {
        logger.log(`task-${type}-email-failure`, "error", null, null, error);
      }
    }
  );
};

/**
 * Email the assigned user.
 * @param req
 * @param res
 * @returns {Promise<*>}
 */
const taskAssignedEmail = async (req, res) => {
  // We have no event Data, bail
  if (!req?.body?.event?.data?.new) {
    return res.status(400).json({ message: "No data in the event body" });
  }

  const { new: newTask } = req.body.event.data;

  // This is not a new task, but a reassignment.
  const dirty = req.body.event.data?.old && req.body.event.data?.old?.assigned_to;

  //Query to get the employee assigned currently.
  const { tasks_by_pk } = await client.request(queries.QUERY_TASK_BY_ID, {
    id: newTask.id
  });

  const dateLine = moment().tz(tasks_by_pk.bodyshop.timezone).format("M/DD/YYYY @ hh:mm a");

  sendMail(
    "assigned",
    tasks_by_pk.assigned_to_employee.user_email,
    `A ${formatTaskPriority(newTask.priority)} priority task has been ${dirty ? "reassigned to" : "created for"} you - ${newTask.title}`,
    generateEmailTemplate(
      generateTemplateArgs(
        newTask.title,
        newTask.priority,
        newTask.description,
        newTask.due_date,
        tasks_by_pk.bodyshop,
        tasks_by_pk.job,
        newTask.id,
        dateLine,
        newTask.created_by
      )
    ),
    null,
    null,
    tasks_by_pk.bodyshop.convenient_company
  );

  // We return success regardless because we don't want to block the event trigger.
  res.status(200).json({ success: true });
};

/**
 * Email remind the user of their tasks.
 * @param req
 * @param res
 * @returns {Promise<*>}
 */
const tasksRemindEmail = async (req, res) => {
  try {
    const tasksRequest = await client.request(queries.QUERY_REMIND_TASKS, {
      time: moment().add(1, "minutes").toISOString()
    });

    // No tasks present in the database, bail.
    if (!tasksRequest?.tasks || !tasksRequest?.tasks.length) {
      return res.status(200).json({ message: "No tasks to remind" });
    }

    // Group tasks by assigned_to, to avoid sending multiple emails to the same recipient.
    const groupedTasks = tasksRequest.tasks.reduce((acc, task) => {
      const key = task.assigned_to_employee.user_email;
      if (!acc[key]) {
        acc[key] = [];
      }
      acc[key].push(task);
      return acc;
    }, {});

    // No grouped tasks, bail.
    if (Object.keys(groupedTasks).length === 0) {
      return res.status(200).json({ message: "No tasks to remind" });
    }

    // Build an aggregate data object containing  email and the count of tasks assigned to them.
    const recipientCounts = Object.keys(groupedTasks).map((key) => {
      return {
        email: key,
        count: groupedTasks[key].length
      };
    });

    // Iterate over all recipients and send the email.
    recipientCounts.forEach((recipient) => {
      const fromEmails = InstanceManager({
        imex: "ImEX Online <noreply@imex.online>",
        rome: "Rome Online <noreply@romeonline.io>"
      });

      const emailData = {
        from: fromEmails,
        to: recipient.email
      };

      const taskIds = groupedTasks[recipient.email].map((task) => task.id);

      const dateLine = moment().tz(tasksRequest?.tasks[0].bodyshop.timezone).format("M/DD/YYYY @ hh:mm a");

      // There is only the one email to send to this author.
      if (recipient.count === 1) {
        const onlyTask = groupedTasks[recipient.email][0];

        emailData.subject =
          `New ${formatTaskPriority(onlyTask.priority)} Priority Task Reminder - ${onlyTask.title} ${onlyTask.due_date ? `- ${formatDate(onlyTask.due_date)}` : ""}`.trim();

        emailData.html = generateEmailTemplate(
          generateTemplateArgs(
            onlyTask.title,
            onlyTask.priority,
            onlyTask.description,
            onlyTask.due_date,
            onlyTask.bodyshop,
            onlyTask.job,
            onlyTask.id,
            dateLine,
            onlyTask.created_by
          )
        );
      }
      // There are multiple emails to send to this author.
      else {
        const allTasks = groupedTasks[recipient.email];
        emailData.subject = `New Tasks Reminder - ${allTasks.length} Tasks require your attention`;
        emailData.html = generateEmailTemplate({
          header: `${allTasks.length} Tasks require your attention`,
          subHeader: `Please click on the Tasks below to view the Task.`,
          dateLine,
          body: `
            <ul style="font-family: 'Montserrat', 'Montserrat Alternates', sans-serif; font-size: 90%; margin: 1%; padding-left: 30px;">
              ${allTasks
                .map((task) =>
                  `
                    <li style="font-family: 'Montserrat', 'Montserrat Alternates', sans-serif; font-size: 90%;">
                      <a href="${InstanceEndpoints()}/manage/tasks/alltasks?taskid=${task.id}" style="color: #2199e8; text-decoration: none; font-weight: normal; padding: 0; text-align: left; font-family: 'Montserrat', 'Montserrat Alternates', sans-serif; font-size: 90%; line-height: 1.2;">${task.title} - Priority: ${formatTaskPriority(task.priority)} ${task.due_date ? `${formatDate(task.due_date)}` : ""} | Bodyshop: ${task.bodyshop.shopname}</a>
                    </li>
                  `.trim()
                )
                .join("")}
            </ul>`
        });
      }

      if (emailData?.subject && emailData?.html) {
        // Send Email
        sendMail(
          "remind",
          emailData.to,
          emailData.subject,
          emailData.html,
          taskIds,
          (taskIds) => {
            for (const taskId of taskIds) {
              tasksEmailQueue.push(taskId);
            }
          },
          tasksRequest?.tasks[0].bodyshop.convenient_company
        );
      }
    });

    // Sixth step would be to set the remind_at_sent to the current time.
    res.status(200).json({ status: "success" });
  } catch (err) {
    res.status(500).json({
      status: "error",
      message: `Something went wrong sending Task Reminders: ${err.message || "An error occurred"}`
    });
  }
};

// Note: Uncomment this to test locally, it will call the remind_at email check every 20 seconds
// const callTaskRemindEmailInternally = () => {
//   const req = {
//     body: {
//       // You can mock any request data here if needed
//     }
//   };
//
//   const res = {
//     status: (code) => {
//       return {
//         json: (data) => {
//           console.log(`Response Status: ${code}`, data);
//         }
//       };
//     }
//   };
//
//   // Call the taskRemindEmail function with mock req and res
//   tasksRemindEmail(req, res);
// };
// setInterval(callTaskRemindEmailInternally, 20000);

module.exports = {
  taskAssignedEmail,
  tasksRemindEmail
};
