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

/**
 * Get action required notifications for the logged-in user
 * Shows pending and in-progress tasks assigned to the user
 */
const getActionRequired = async (req, res) => {
  try {
    const userId = req.user.id;
    const { status, entityType, limit = 50 } = req.query;

    // Build where clause
    const whereClause = {
      userId: userId,
    };

    // Filter by status (default: pending and in-progress)
    if (status) {
      whereClause.status = status;
    } else {
      whereClause.status = {
        [Op.in]: ["pending", "in-progress"],
      };
    }

    // Filter by entity type if provided
    if (entityType) {
      whereClause.entityType = entityType;
    }

    // Check if Notification table exists, if not return empty data
    let notifications = [];
    try {
      // Fetch notifications
      notifications = await Notification.findAll({
        where: whereClause,
        include: [
          {
            model: Users,
            as: "Assigner",
            attributes: ["id", "fullname", "email"],
          },
          {
            model: Projects,
            attributes: ["id", "name"],
            required: false,
          },
        ],
        order: [
          ["createdAt", "DESC"], // Newest first (most recent notifications at top)
          ["priority", "DESC"], // Then by priority (urgent first)
          ["dueDate", "ASC"], // Then by earliest due date
        ],
        limit: parseInt(limit),
      });
    } catch (dbError) {
      // If table doesn't exist, return empty data
      console.warn("Notifications table may not exist:", dbError.message);
      return res.json({
        notifications: [],
        summary: {
          total: 0,
          byStatus: {
            pending: 0,
            inProgress: 0,
          },
          byPriority: {
            urgent: 0,
            high: 0,
            medium: 0,
            low: 0,
          },
          overdue: 0,
          unread: 0,
        },
        message: "Notifications table not found. Please run the SQL migration script.",
      });
    }

    // Format response
    const formattedNotifications = notifications.map((notification) => {
      const assigner = notification.Assigner;
      const project = notification.Project;

      // Calculate if overdue
      const isOverdue =
        notification.dueDate && new Date(notification.dueDate) < new Date();

      // Format due date
      const formatDueDate = (date) => {
        if (!date) return null;
        const d = new Date(date);
        const month = d.getMonth() + 1;
        const day = d.getDate();
        const year = d.getFullYear();
        return `${month}/${day}/${year}`;
      };

      return {
        id: notification.id,
        taskNumber: notification.taskNumber,
        title: notification.title,
        description: notification.description,
        entityType: notification.entityType,
        entityId: notification.entityId,
        status: notification.status,
        priority: notification.priority,
        dueDate: formatDueDate(notification.dueDate),
        dueDateRaw: notification.dueDate,
        isOverdue: isOverdue,
        assignedBy: assigner
          ? {
              id: assigner.id,
              name: assigner.fullname,
              email: assigner.email,
            }
          : null,
        project: project
          ? {
              id: project.id,
              name: project.name,
            }
          : null,
        isRead: notification.isRead,
        readAt: notification.readAt,
        createdAt: notification.createdAt,
        metadata: notification.metadata,
      };
    });

    // Calculate summary
    const summary = {
      total: formattedNotifications.length,
      byStatus: {
        pending: formattedNotifications.filter((n) => n.status === "pending")
          .length,
        inProgress: formattedNotifications.filter(
          (n) => n.status === "in-progress"
        ).length,
      },
      byPriority: {
        urgent: formattedNotifications.filter((n) => n.priority === "urgent")
          .length,
        high: formattedNotifications.filter((n) => n.priority === "high")
          .length,
        medium: formattedNotifications.filter((n) => n.priority === "medium")
          .length,
        low: formattedNotifications.filter((n) => n.priority === "low").length,
      },
      overdue: formattedNotifications.filter((n) => n.isOverdue).length,
      unread: formattedNotifications.filter((n) => !n.isRead).length,
    };

    res.json({
      notifications: formattedNotifications,
      summary,
    });
  } catch (error) {
    console.error("Error fetching action required notifications:", error);
    res.status(500).json({
      message: "Failed to fetch notifications",
      error: error.message,
    });
  }
};

/**
 * Get notification count (for badge)
 */
const getNotificationCount = async (req, res) => {
  try {
    const userId = req.user.id;

    let count = 0;
    try {
      count = await Notification.count({
        where: {
          userId: userId,
          status: {
            [Op.in]: ["pending", "in-progress"],
          },
          isRead: false,
        },
      });
    } catch (dbError) {
      // If table doesn't exist, return 0
      console.warn("Notifications table may not exist:", dbError.message);
      count = 0;
    }

    res.json({ count });
  } catch (error) {
    console.error("Error fetching notification count:", error);
    res.json({ count: 0 }); // Return 0 instead of error to avoid breaking UI
  }
};

/**
 * Mark notification as read
 */
const markAsRead = async (req, res) => {
  try {
    const { id } = req.params;
    const userId = req.user.id;

    const notification = await Notification.findOne({
      where: {
        id: id,
        userId: userId,
      },
    });

    if (!notification) {
      return res.status(404).json({ message: "Notification not found" });
    }

    // Update using Notification.update() instead of instance method
    await Notification.update(
      {
        isRead: true,
        readAt: new Date(),
      },
      {
        where: {
          id: id,
          userId: userId,
        },
      }
    );

    // Fetch updated notification
    const updatedNotification = await Notification.findByPk(id);

    res.json({
      message: "Notification marked as read",
      notification: {
        id: updatedNotification.id,
        isRead: updatedNotification.isRead,
        readAt: updatedNotification.readAt,
      },
    });
  } catch (error) {
    console.error("Error marking notification as read:", error);
    res.status(500).json({
      message: "Failed to mark notification as read",
      error: error.message,
    });
  }
};

/**
 * Mark all notifications as read
 */
const markAllAsRead = async (req, res) => {
  try {
    const userId = req.user.id;
    
    console.log(`Marking all notifications as read for user ${userId}`);

    const result = await Notification.update(
      {
        isRead: true,
        readAt: new Date(),
      },
      {
        where: {
          userId: userId,
          isRead: false,
        },
      }
    );

    console.log(`Updated ${result[0]} notifications for user ${userId}`);

    res.json({ 
      message: "All notifications marked as read",
      count: result[0]
    });
  } catch (error) {
    console.error("Error marking all notifications as read:", error);
    res.status(500).json({
      message: "Failed to mark all notifications as read",
      error: error.message,
    });
  }
};

/**
 * Update notification status (e.g., mark as in-progress or completed)
 */
const updateNotificationStatus = async (req, res) => {
  try {
    const { id } = req.params;
    const { status } = req.body;
    const userId = req.user.id;

    // Validate status
    const validStatuses = ["pending", "in-progress", "completed", "cancelled"];
    if (!validStatuses.includes(status)) {
      return res.status(400).json({
        message: `Invalid status. Must be one of: ${validStatuses.join(", ")}`,
      });
    }

    const notification = await Notification.findOne({
      where: {
        id: id,
        userId: userId,
      },
    });

    if (!notification) {
      return res.status(404).json({ message: "Notification not found" });
    }

    const updateData = {
      status: status,
    };

    // If marking as completed, set completedAt
    if (status === "completed") {
      updateData.completedAt = new Date();
    }

    await notification.update(updateData);

    res.json({
      message: "Notification status updated",
      notification: {
        id: notification.id,
        status: notification.status,
        completedAt: notification.completedAt,
      },
    });
  } catch (error) {
    console.error("Error updating notification status:", error);
    res.status(500).json({
      message: "Failed to update notification status",
      error: error.message,
    });
  }
};

/**
 * Create a notification (used when assigning tasks)
 * This is typically called from other controllers when assigning reports/SDS
 */
const createNotification = async (req, res) => {
  try {
    const {
      userId,
      entityType,
      entityId,
      title,
      description,
      priority,
      dueDate,
      projectId,
      metadata,
    } = req.body;

    // Validate required fields
    if (!userId || !entityType || !entityId || !title) {
      return res.status(400).json({
        message: "Missing required fields: userId, entityType, entityId, title",
      });
    }

    // Validate entity type
    const validEntityTypes = [
      "Deviations",
      "Site Monitoring",
      "Case Investigation",
      "SDS",
    ];
    if (!validEntityTypes.includes(entityType)) {
      return res.status(400).json({
        message: `Invalid entity type. Must be one of: ${validEntityTypes.join(", ")}`,
      });
    }

    // Generate task number
    const count = await Notification.count({
      where: { entityType: entityType },
    });
    const taskNumber = `Task #${String(count + 1).padStart(3, "0")}`;

    // Create notification
    const notification = await Notification.create({
      userId: userId,
      assignedBy: req.user.id,
      companyId: req.user.companyId,
      projectId: projectId || null,
      entityType: entityType,
      entityId: entityId,
      taskNumber: taskNumber,
      title: title,
      description: description || null,
      priority: priority || "medium",
      dueDate: dueDate || null,
      status: "pending",
      isRead: false,
      metadata: metadata || null,
    });

    res.status(201).json({
      message: "Notification created successfully",
      notification: {
        id: notification.id,
        taskNumber: notification.taskNumber,
        userId: notification.userId,
        entityType: notification.entityType,
        title: notification.title,
        status: notification.status,
      },
    });
  } catch (error) {
    console.error("Error creating notification:", error);
    res.status(500).json({
      message: "Failed to create notification",
      error: error.message,
    });
  }
};

module.exports = {
  getActionRequired,
  getNotificationCount,
  markAsRead,
  markAllAsRead,
  updateNotificationStatus,
  createNotification,
};
