const { Op } = require("sequelize");
const { Notification, Users } = require("../models");

/**
 * Notification Helper Utility
 * Automatically creates notifications for various system events
 */

/**
 * Generate task number for a notification
 */
const generateTaskNumber = async (entityType) => {
  try {
    const count = await Notification.count({
      where: { entityType: entityType },
    });
    return `Task #${String(count + 1).padStart(3, "0")}`;
  } catch (error) {
    console.error("Error generating task number:", error);
    return `Task #001`;
  }
};

/**
 * Create notification when a report is assigned to a user
 */
const createReportAssignmentNotification = async ({
  userId,
  assignedBy,
  companyId,
  projectId,
  reportType,
  reportId,
  formattedId,
  priority = "medium",
  dueDate = null,
}) => {
  try {
    // Map report types to entity types
    const entityTypeMap = {
      deviations: "Deviations",
      "case-investigations": "Case Investigation",
      "site-monitoring": "Site Monitoring",
    };

    const entityType = entityTypeMap[reportType] || reportType;
    const taskNumber = await generateTaskNumber(entityType);

    // Calculate default due date (3 weeks from now) if not provided
    if (!dueDate) {
      dueDate = new Date();
      dueDate.setDate(dueDate.getDate() + 21);
    }

    const notification = await Notification.create({
      userId: userId,
      assignedBy: assignedBy,
      companyId: companyId,
      projectId: projectId,
      entityType: entityType,
      entityId: reportId,
      taskNumber: taskNumber,
      title: `New ${entityType} assigned to you`,
      description: `You have been assigned to ${entityType} ${formattedId}. Please review and take necessary action.`,
      priority: priority,
      dueDate: dueDate,
      status: "pending",
      isRead: false,
      metadata: {
        reportType: reportType,
        formattedId: formattedId,
      },
    });

    console.log(`✓ Notification created: ${taskNumber} for user ${userId}`);
    return notification;
  } catch (error) {
    console.error("Failed to create report assignment notification:", error);
    // Don't throw error - notification failure shouldn't break the main operation
    return null;
  }
};

/**
 * Create notification when SDS is saved
 */
const createSDSNotification = async ({
  userId,
  assignedBy,
  companyId,
  projectId,
  sdsId,
  productName,
  formattedId,
}) => {
  try {
    const taskNumber = await generateTaskNumber("SDS");

    const notification = await Notification.create({
      userId: userId,
      assignedBy: assignedBy,
      companyId: companyId,
      projectId: projectId,
      entityType: "SDS",
      entityId: sdsId,
      taskNumber: taskNumber,
      title: `New SDS document available: ${productName}`,
      description: `A new Safety Data Sheet (${formattedId}) has been added to your project: ${productName}`,
      priority: "low",
      status: "pending",
      isRead: false,
      metadata: {
        productName: productName,
        formattedId: formattedId,
      },
    });

    console.log(`✓ SDS Notification created: ${taskNumber}`);
    return notification;
  } catch (error) {
    console.error("Failed to create SDS notification:", error);
    return null;
  }
};

/**
 * Create notification when Risk Assessment is created
 */
const createRiskAssessmentNotification = async ({
  userIds, // Array of user IDs (participants)
  assignedBy,
  companyId,
  projectId,
  riskAssessmentId,
  title,
  formattedId,
  priority = "high",
}) => {
  try {
    const notifications = [];

    for (const userId of userIds) {
      const taskNumber = await generateTaskNumber("Risk Assessment");

      const notification = await Notification.create({
        userId: userId,
        assignedBy: assignedBy,
        companyId: companyId,
        projectId: projectId,
        entityType: "Risk Assessment",
        entityId: riskAssessmentId,
        taskNumber: taskNumber,
        title: `Risk Assessment requires your attention`,
        description: `You are a participant in Risk Assessment ${formattedId}: ${title}`,
        priority: priority,
        status: "pending",
        isRead: false,
        metadata: {
          riskAssessmentTitle: title,
          formattedId: formattedId,
        },
      });

      notifications.push(notification);
      console.log(`✓ Risk Assessment notification created: ${taskNumber} for user ${userId}`);
    }

    return notifications;
  } catch (error) {
    console.error("Failed to create risk assessment notification:", error);
    return [];
  }
};

/**
 * Create notification when Job Safety Analysis is created
 */
const createJSANotification = async ({
  userIds, // Array of user IDs (contributors)
  assignedBy,
  companyId,
  projectId,
  jsaId,
  taskActivity,
  formattedId,
  priority = "high",
}) => {
  try {
    const notifications = [];

    for (const userId of userIds) {
      const taskNumber = await generateTaskNumber("Job Safety Analysis");

      const notification = await Notification.create({
        userId: userId,
        assignedBy: assignedBy,
        companyId: companyId,
        projectId: projectId,
        entityType: "Job Safety Analysis",
        entityId: jsaId,
        taskNumber: taskNumber,
        title: `Job Safety Analysis requires your attention`,
        description: `You are a contributor to JSA ${formattedId}: ${taskActivity}`,
        priority: priority,
        status: "pending",
        isRead: false,
        metadata: {
          taskActivity: taskActivity,
          formattedId: formattedId,
        },
      });

      notifications.push(notification);
      console.log(`✓ JSA notification created: ${taskNumber} for user ${userId}`);
    }

    return notifications;
  } catch (error) {
    console.error("Failed to create JSA notification:", error);
    return [];
  }
};

/**
 * Create notification when a user is invited or assigned to a training module (optional workflow).
 * Uses entityType "Training" (must exist on Notification model + DB ENUM).
 */
const createTrainingInviteNotification = async ({
  userId,
  assignedBy,
  companyId,
  projectId,
  trainingVideoId,
  videoTitle,
  formattedId,
  priority = "medium",
  dueDate = null,
}) => {
  try {
    const taskNumber = await generateTaskNumber("Training");

    if (!dueDate) {
      dueDate = new Date();
      dueDate.setDate(dueDate.getDate() + 21);
    }

    const notification = await Notification.create({
      userId,
      assignedBy: assignedBy ?? null,
      companyId,
      projectId: projectId ?? null,
      entityType: "Training",
      entityId: trainingVideoId,
      taskNumber,
      title: `Training assigned: ${videoTitle || "module"}`,
      description: formattedId
        ? `You have been assigned training ${formattedId}. Complete the video and quiz in the Training Portal.`
        : `You have been assigned a training module. Complete it in the Training Portal.`,
      priority,
      dueDate,
      status: "pending",
      isRead: false,
      metadata: {
        trainingVideoId,
        formattedId: formattedId || null,
        videoTitle: videoTitle || null,
      },
    });

    console.log(`✓ Training notification created: ${taskNumber} for user ${userId}`);
    return notification;
  } catch (error) {
    console.error("Failed to create training invite notification:", error);
    return null;
  }
};

/**
 * Notify HR (or admins if no HR) when an employee submits a leave request.
 */
const createLeaveRequestNotification = async ({
  leaveRequestId,
  employeeId,
  employeeName,
  companyId,
  leaveType,
  startDate,
  endDate,
}) => {
  try {
    let recipients = await Users.findAll({
      where: { CompanyId: companyId, role: "hr" },
      attributes: ["id"],
    });
    if (!recipients.length) {
      recipients = await Users.findAll({
        where: { CompanyId: companyId, role: { [Op.in]: ["admin", "super-admin"] } },
        attributes: ["id"],
      });
    }
    const sd = startDate instanceof Date ? startDate.toISOString().slice(0, 10) : String(startDate);
    const ed = endDate instanceof Date ? endDate.toISOString().slice(0, 10) : String(endDate);
    const title = `New leave request from ${employeeName}`;
    const description = `${employeeName} has requested ${leaveType} from ${sd} to ${ed}`;

    for (const r of recipients) {
      const taskNumber = await generateTaskNumber("Leave Request");
      await Notification.create({
        userId: r.id,
        assignedBy: employeeId,
        companyId,
        projectId: null,
        entityType: "Leave Request",
        entityId: leaveRequestId,
        taskNumber,
        title,
        description,
        priority: "medium",
        status: "pending",
        isRead: false,
        metadata: { leaveType, startDate: sd, endDate: ed },
      });
    }
    console.log(`✓ Leave request notifications created for ${recipients.length} recipient(s)`);
    return true;
  } catch (error) {
    console.error("Failed to create leave request notifications:", error);
    return null;
  }
};

/**
 * Notify employee when HR approves or rejects their leave.
 */
const createLeaveResponseNotification = async ({
  leaveRequestId,
  employeeId,
  reviewerId,
  companyId,
  status,
  reviewNote,
  leaveType,
  startDate,
  endDate,
}) => {
  try {
    const taskNumber = await generateTaskNumber("Leave Request");
    const sd = startDate instanceof Date ? startDate.toISOString().slice(0, 10) : String(startDate);
    const ed = endDate instanceof Date ? endDate.toISOString().slice(0, 10) : String(endDate);
    const title =
      status === "approved" ? "Your leave request was approved" : "Your leave request was rejected";
    const description =
      status === "approved"
        ? `Your ${leaveType} from ${sd} to ${ed} has been approved.`
        : `Your ${leaveType} from ${sd} to ${ed} was rejected.${reviewNote ? ` Note: ${reviewNote}` : ""}`;

    await Notification.create({
      userId: employeeId,
      assignedBy: reviewerId,
      companyId,
      projectId: null,
      entityType: "Leave Request",
      entityId: leaveRequestId,
      taskNumber,
      title,
      description,
      priority: "medium",
      status: "pending",
      isRead: false,
      metadata: { decision: status, reviewNote: reviewNote || null },
    });
    console.log(`✓ Leave response notification for user ${employeeId}`);
    return true;
  } catch (error) {
    console.error("Failed to create leave response notification:", error);
    return null;
  }
};

/**
 * Notify user when assigned to a training course by an admin (explicit assignment flow).
 */
const createTrainingAssignmentNotification = async ({
  userId,
  assignedBy,
  assignedByName,
  companyId,
  videoId,
  videoTitle,
}) => {
  try {
    const taskNumber = await generateTaskNumber("Training");
    const dueDate = new Date();
    dueDate.setDate(dueDate.getDate() + 21);

    await Notification.create({
      userId,
      assignedBy,
      companyId,
      projectId: null,
      entityType: "Training",
      entityId: videoId,
      taskNumber,
      title: "You have been assigned a training course",
      description: `${assignedByName} has assigned you to complete: ${videoTitle}. Please watch the video and complete the quiz.`,
      priority: "medium",
      status: "pending",
      isRead: false,
      dueDate,
      metadata: { trainingVideoId: videoId, videoTitle },
    });
    console.log(`✓ Training assignment notification for user ${userId}`);
    return true;
  } catch (error) {
    console.error("Failed to create training assignment notification:", error);
    return null;
  }
};

module.exports = {
  createReportAssignmentNotification,
  createSDSNotification,
  createRiskAssessmentNotification,
  createJSANotification,
  createTrainingInviteNotification,
  createLeaveRequestNotification,
  createLeaveResponseNotification,
  createTrainingAssignmentNotification,
  generateTaskNumber,
};
