// controllers/admin/taskController.js
const Task = require("../models/taskModel");
const { errorResponse } = require("../utils/errorResponseHandler");
const { logUserAction } = require("../utils/userActionLogger");
const XLSX = require("xlsx")
const fs = require("fs")
const path = require('path')
const User = require("../models/userModel");
const mongoose = require("mongoose"); // ✅ ADD THIS
const Service = require("../models/admin/serviceModal");
const { createNotification } = require("../services/notification.service");




// ------------------ CREATE TASK ------------------
const createTask = async (req, res) => {
  try {
    const files = req.files || [];
    const userId = req.user._id;

    // Map FormData fields to schema
    const {
      taskName,
      description,
      mobile,
      // dueDate,
      status,
      priority,
      customerNumber,
      customerName,
      sla,
      assignedTo,
      location,
      orgId,
      service,
      customer,
    } = req.body;

    const initialStatus = assignedTo ? "Assigned" : "Pending";

    if (!service) {
      return res.status(400).json({ message: "Service is required" });
    }
    const serviceDoc = await Service.findById(service);
    if (!serviceDoc) {
      return res.status(400).json({ message: "Invalid service selected" });
    }


    const serviceName = serviceDoc.serviceName;
    const serviceCost = serviceDoc.serviceCost;

    if (!req.body.dueDate) {
      return res.status(400).json({ message: "Due date is required" });
    }

    const dueDate = new Date(req.body.dueDate);
    const now = new Date();

    if (isNaN(dueDate.getTime())) {
      return res.status(400).json({ message: "Invalid date format" });
    }

    if (dueDate.getTime() < now.getTime()) {
      return res.status(400).json({ message: "Past date/time is not allowed" });
    }

    // if (new Date(req.body.dueDate) < new Date()) {
    //   return res.status(400).json({
    //     message: "Past date/time is not allowed",
    //   });
    // }
    // console.log(customer); //it is returning a object
    const task = await Task.create({
      taskName,
      description,
      mobile,
      dueDate,
      status: initialStatus,
      priority,
      sla,
      assignedTo: assignedTo || null,
      assignedBy: userId,
      currentAssignee: assignedTo || null,
      currentStatus: initialStatus,
      orgId,
      // service,
      // 🔥 SERVICE SNAPSHOT
      service: serviceDoc._id,
      serviceName: serviceName,
      serviceCost: serviceCost,

      location,
      customer: {
        name: customerName,
        phone: customerNumber,
      },
      attachments: files.map(file => ({
        fileName: file.originalname,
        fileUrl: `/uploads/images/${file.filename}`,
      })),
      createdBy: userId,
      updatedBy: null,
    });

    // Update assignment history & task events
    if (assignedTo) {
      task.assignmentHistory.push({
        assignedTo,
        assignedBy: userId,
        assignedAt: new Date(),
        previousStatus: "Pending",
        newStatus: "Assigned",
      });
      task.taskEvents.push({
        type: "Assigned",
        details: `Task assigned to agent ${assignedTo}`,
        by: userId,
      });
      await task.save();

      //  CREATE NOTIFICATION
      try {
        await createNotification({
          userId: assignedTo, // agent assignedTo
          orgId: task.orgId,
          title: "Work Assigned",
          message: `Please complete the ${task.serviceName} task at ${task.location}`,
          type: "TASK_ASSIGNED",
          metadata: {
            taskId: task._id,
          },
        });
      } catch (notifyErr) {
        console.error(
          "Notification failed, task still created:",
          notifyErr.message
        );
        // ❌ DO NOT throw
      }
    }

    return res.status(201).json({
      success: true,
      message: "Task created successfully",
      data: task,
    });
  } catch (err) {
    console.error(err);
    return res.status(500).json({ success: false, message: "Failed to create task", error: err.message });
  }
};

// my post api for create task
// const createTaskOne = async (req,res)=>{
//   try {
//     const {taskName, description, mobile, dueDate, status, priority, sla, location, orgId, customer} = req.body;
//     const task = await Task.create({
//       taskName,
//       description,
//       mobile,   
//       dueDate,
//       status,
//       priority,
//       sla,
//       // assignedTo,
//       location,
//       orgId,
//       customer,
//     })
//     await task.save();
//     return res.status(201).json({
//       success : true,
//       msg : "Task created successfully",
//       data : task,
//     })

//   }
//   catch (err) {
//     console.error(err);
//     return res.status(500).json({
//       success : false,
//       msg : "Failed to create task",
//       error :  err.message
//     })
//   }
// }

// getTaskById by me
// const getTaskByIdOne = async (req,res) =>{
//      try {
//       // const id = req.params._id;
//       const task = await Task.findById(req.params.id)
//       if(!task) {
//         return res.status(404).json({
//           success : false,
//           msg : "Task not found", 
//         })
//       }
//       return res.status(200).json({
//         success : true,
//         msg : "Task fetched successfully",
//         data : task,
//       })

//      } catch (error) {
//       console.error(error);
//       return res.status(500).json({ success: false, message: "Failed to fetch task", error: error.message });
//      }
// }


// ------------------ GET TASK BY ID ------------------
const getTaskById = async (req, res) => {
  try {
    const task = await Task.findById(req.params.id)
      .populate("assignedTo", "firstName email phone role")
      .populate("service", "serviceName serviceCost")
      .populate("assignedBy", "firstName email")
      .populate("createdBy", "firstName")
      .populate("updatedBy", "firstName");

    if (!task) return errorResponse(res, "Task not found", 404);

    await logUserAction({
      userId: req.user?._id,
      // userId: req.user.id,
      action: "READ",
      model: "Task",
      details: { taskId: task._id },
      req,
    });

    return res.json({
      success: true,
      message: "Task fetched successfully",
      data: task,
    });
  } catch (err) {
    return errorResponse(res, "Failed to fetch task", 500, err);
  }
};

// ------------------ GET ALL TASKS ------------------
const getTasks = async (req, res) => {
  try {
    let { page = 1, limit = 10 } = req.query;
    page = parseInt(page);
    limit = parseInt(limit);
    const skip = (page - 1) * limit;

    const query = { isDeleted: false };

    const [tasks, total] = await Promise.all([
      Task.find(query).populate("assignedTo", "firstName lastName")
        .populate("service", "serviceName serviceCost")
        .populate("assignedBy", "firstName lastName")
        .populate("createdBy", "firstName lastName").skip(skip).limit(limit).sort({ createdAt: -1 }),
      Task.countDocuments(query),
    ]);

    await logUserAction({
      // userId: req.user?._id,
      userId: req.user.id,
      action: "READ",
      model: "Task",
      details: { page, limit, count: tasks.length },
      req,
    });

    return res.json({
      success: true,
      total,
      page,
      totalPages: Math.ceil(total / limit),
      data: tasks,
    });
  } catch (err) {
    return errorResponse(res, "Failed to fetch tasks", 500, err);
  }
};


// ------------------ UPDATE TASK ------------------
// const updateTask = async (req, res) => {
//   try {
//     const userId = req.user._id;
//     const taskId = req.params.id;

//     const {
//       taskName,
//       description,
//       priority,
//       status,
//       dueDate,
//       assignedTo,
//       service,
//       customer,
//     } = req.body;

//     const task = await Task.findById(taskId);
//     if (!task) return errorResponse(res, "Task not found", 404);

//     //  Due date validation (same rule as create)
//     // if (dueDate) {
//     //   const parsedDate = new Date(dueDate);
//     //   if (isNaN(parsedDate.getTime())) {
//     //     return errorResponse(res, "Invalid due date format", 400);
//     //   }
//     //   if (parsedDate < new Date()) {
//     //     return errorResponse(res, "Past date/time is not allowed", 400);
//     //   }
//     //   task.dueDate = parsedDate;
//     // }



//     //  Safe field updates
//     if (taskName) task.taskName = taskName;
//     if (description) task.description = description;
//     if (priority) task.priority = priority;
//     if (status) task.status = status;
//     // if (service) task.service = service;

//     if (service && String(service) !== String(task.service)) {
//       const serviceDoc = await Service.findById(service);
//       if (!serviceDoc) {
//         return errorResponse(res, "Invalid service selected", 400);
//       }

//       // Update reference
//       task.service = serviceDoc._id;

//       // 🔒 Snapshot (billing safe)
//       task.serviceName = serviceDoc.serviceName;
//       task.serviceCost = serviceDoc.serviceCost;
//     }

//     if (customer) {
//       task.customer = {
//         name: customer.name,
//         phone: customer.phone,
//       };
//     }

//     //  Assignment handling (CRITICAL)
//     if (assignedTo && assignedTo !== String(task.currentAssignee)) {
//       task.assignmentHistory.push({
//         assignedTo,
//         assignedBy: userId,
//         assignedAt: new Date(),
//         previousStatus: task.currentStatus,
//       });

//       task.taskEvents.push({
//         type: "Reassigned",
//         details: `Task reassigned to user ${assignedTo}`,
//         by: userId,
//       });

//       task.assignedTo = assignedTo;
//       task.currentAssignee = assignedTo;
//     }

//     task.updatedBy = userId;

//     await task.save();

//     await logUserAction({
//       userId,
//       action: "UPDATE",
//       model: "Task",
//       details: {
//         taskId: task._id,
//         updatedFields: req.body,
//       },
//       req,
//     });

//     return res.json({
//       success: true,
//       message: "Task updated successfully",
//       data: task,
//     });
//   } catch (err) {
//     console.error(err);
//     return errorResponse(res, "Failed to update task", 500, err);
//   }
// };
const updateTask = async (req, res) => {
  try {
    const userId = req.user._id;
    const taskId = req.params.id;

    const {
      taskName,
      description,
      priority,
      status,
      dueDate,
      assignedTo,
      service,
      customer,
    } = req.body;

    const task = await Task.findById(taskId);
    if (!task) return errorResponse(res, "Task not found", 404);

    /* ---------------- SAFE UPDATES ---------------- */
    if (taskName) task.taskName = taskName;
    if (description) task.description = description;
    if (priority) task.priority = priority;
    if (status) task.status = status;
    if (dueDate) task.dueDate = dueDate;

    /* ---------------- SERVICE SNAPSHOT (CRITICAL) ---------------- */
    if (!task.serviceName || !task.serviceCost || service) {
      const serviceId = service || task.service;
      const serviceDoc = await Service.findById(serviceId);

      if (!serviceDoc) {
        return errorResponse(res, "Invalid service selected", 400);
      }

      task.service = serviceDoc._id;
      task.serviceName = serviceDoc.serviceName;
      task.serviceCost = serviceDoc.serviceCost;
      task.serviceSnapshotAt = new Date();
    }

    /* ---------------- CUSTOMER ---------------- */
    if (customer) {
      task.customer = {
        name: customer.name,
        phone: customer.phone,
      };
    }

    /* ---------------- ASSIGNMENT ---------------- */
    if (assignedTo && String(assignedTo) !== String(task.currentAssignee)) {
      task.assignmentHistory.push({
        assignedTo,
        assignedBy: userId,
        previousStatus: task.status,
        newStatus: task.status, // 🔒 REQUIRED FIELD
      });

      task.taskEvents.push({
        type: "Reassigned",
        details: `Task reassigned to user ${assignedTo}`,
        by: userId,
      });

      task.assignedTo = assignedTo;
      task.currentAssignee = assignedTo;
      task.timesReassigned += 1;
    }

    task.updatedBy = userId;

    await task.save();

    return res.json({
      success: true,
      message: "Task updated successfully",
      data: task,
    });
  } catch (err) {
    console.error(err);
    return errorResponse(res, "Failed to update task", 500, err);
  }
};



// ------------------ DELETE (SOFT) TASK ------------------
const deleteTask = async (req, res) => {
  try {
    const userId = req.user?._id;

    const task = await Task.findByIdAndUpdate(
      req.params.id,
      { isDeleted: true, updatedBy: userId },
      { new: true }
    );

    if (!task) return errorResponse(res, "Task not found", 404);

    await logUserAction({
      userId,
      action: "DELETE",
      model: "Task",
      details: { taskId: task._id },
      req,
    });

    return res.json({
      success: true,
      message: "Task deleted successfully",
      data: task,
    });
  } catch (err) {
    return errorResponse(res, "Failed to delete task", 500, err);
  }
};

// ------------------ REASSIGN TASK ------------------
// const reassignTask = async (req, res) => {
//   try {
//     const { newAssignee } = req.body;
//     const userId = req.user?._id;

//     const task = await Task.findById(req.params.id);
//     if (!task) return errorResponse(res, "Task not found", 404);
//     if (!newAssignee) return errorResponse(res, "New assignee is required", 400);

//     // Update assignment history
//     task.assignmentHistory.push({
//       assignedTo: newAssignee,
//       assignedBy: userId,
//       assignedAt: new Date(),
//       previousStatus: task.currentStatus,
//     });

//     task.currentAssignee = newAssignee;
//     task.assignedTo = newAssignee;
//     task.isRevoked = false;
//     task.timesReassigned = (task.timesReassigned || 0) + 1;

//     // Add event
//     task.taskEvents.push({
//       type: "Reassigned",
//       details: `Task reassigned to user ${newAssignee}`,
//       by: userId,
//     });

//     await task.save();

//     await logUserAction({
//       userId,
//       action: "REASSIGN",
//       model: "Task",
//       details: { taskId: task._id, newAssignee },
//       req,
//     });

//     return res.json({
//       success: true,
//       message: "Task reassigned successfully",
//       data: task,
//     });
//   } catch (err) {
//     return errorResponse(res, "Failed to reassign task", 500, err);
//   }
// };
const reassignTask = async (req, res) => {
  try {
    const { newAssignee } = req.body;
    const userId = req.user._id;

    const task = await Task.findById(req.params.id);
    if (!task) return errorResponse(res, "Task not found", 404);
    if (!newAssignee)
      return errorResponse(res, "New assignee is required", 400);

    task.assignmentHistory.push({
      assignedTo: newAssignee,
      assignedBy: userId,
      assignedAt: new Date(),
      previousStatus: task.currentStatus,
    });

    task.currentAssignee = newAssignee;
    task.assignedTo = newAssignee;
    task.isRevoked = false;
    task.timesReassigned = (task.timesReassigned || 0) + 1;

    task.taskEvents.push({
      type: "Reassigned",
      details: `Task reassigned`,
      by: userId,
    });

    await task.save();

    // 🔥 IMPORTANT: re-fetch with populate
    const populatedTask = await Task.findById(task._id)
      .populate("assignedTo", "_id name")
      .populate("assignedBy", "_id name");

    await logUserAction({
      userId,
      action: "REASSIGN",
      model: "Task",
      details: { taskId: task._id, newAssignee },
      req,
    });

    return res.json({
      success: true,
      message: "Task reassigned successfully",
      data: populatedTask,
    });
  } catch (err) {
    return errorResponse(res, "Failed to reassign task", 500, err);
  }
};


// ------------------ ASSIGN TASK ------------------
const assignTask = async (req, res) => {
  try {
    const { assignee } = req.body;
    const userId = req.user?._id;

    if (!assignee) return errorResponse(res, "Assignee is required", 400);

    const task = await Task.findById(req.params.id)
      .populate("assignedTo", "firstName lastName")
      .populate("assignedBy", "firstName lastName")
      .populate("createdBy", "firstName lastName");
    if (!task) return errorResponse(res, "Task not found", 404);

    // Update assignment snapshot and history
    task.assignedTo = assignee;
    task.assignedBy = userId;
    task.currentAssignee = assignee;
    task.isRevoked = false;
    task.currentStatus = task.status;

    task.assignmentHistory.push({
      assignedTo: assignee,
      assignedBy: userId,
      assignedAt: new Date(),
      previousStatus: task.currentStatus,
    });

    // Add task event
    task.taskEvents.push({
      type: "Assigned",
      details: `Task assigned to user ${assignee}`,
      by: userId,
    });

    await task.save();

    await logUserAction({
      userId,
      action: "ASSIGN",
      model: "Task",
      details: { taskId: task._id, assignee },
      req,
    });

    return res.json({
      success: true,
      message: "Task assigned successfully",
      data: task,
    });
  } catch (err) {
    return errorResponse(res, "Failed to assign task", 500, err);
  }
};


const revokeTask = async (req, res) => {
  try {
    const userId = req.user?._id;
    const taskId = req.params.id;

    const task = await Task.findById(taskId);
    if (!task) {
      return errorResponse(res, "Task not found", 404);
    }

    // 🚫 Prevent revoking an already unassigned task
    if (!task.assignedTo) {
      return errorResponse(res, "Task is already unassigned", 400);
    }

    // ✅ Safely update assignment history
    if (task.assignmentHistory?.length) {
      const lastAssignment =
        task.assignmentHistory[task.assignmentHistory.length - 1];

      if (!lastAssignment.revokedAt) {
        lastAssignment.revokedAt = new Date();
      }
    }

    // ✅ Update snapshot fields
    task.currentAssignee = null;
    task.assignedTo = null;
    task.isRevoked = true;
    task.revokedBy = userId;        // (optional but recommended)
    task.revokedAt = new Date();    // (optional but recommended)

    // ✅ Add task event
    task.taskEvents.push({
      type: "Revoked",
      details: `Task revoked by user ${userId}`,
      by: userId,
      at: new Date(),
    });

    await task.save();

    // ✅ Audit log
    await logUserAction({
      userId,
      action: "REVOKE",
      model: "Task",
      details: { taskId: task._id },
      req,
    });

    return res.json({
      success: true,
      message: "Task revoked successfully",
      data: task,
    });
  } catch (err) {
    console.error("Revoke Task Error:", err);
    return errorResponse(res, "Failed to revoke task", 500, err);
  }
};


// ------------------ GET TASKS BY ASSIGNEE ------------------
const getTasksByAssignee = async (req, res) => {
  try {
    const userId = req.params.userId;
    const orgId = req.user?.orgId;
    const tasks = await Task.find({ assignedTo: userId, orgId, isDeleted: false }).sort({ createdAt: -1 })
      .populate("assignedTo", "firstName lastName")
      .populate("assignedBy", "firstName lastName")
      .populate("createdBy", "firstName lastName");
    return res.json({ success: true, data: tasks });
  } catch (err) {
    return errorResponse(res, "Failed to fetch tasks by assignee", 500, err);
  }
};

// ------------------ GET TASKS BY ORG ------------------
const getTasksByOrg = async (req, res) => {
  try {
    const orgId = req.params.orgId || req.user?.orgId;

    const tasks = await Task.find({ orgId, isDeleted: false })
      .sort({ createdAt: -1 })
      .populate("assignedTo", "firstName lastName")
      .populate("service", "serviceName")
      .populate("assignedBy", "firstName lastName")
      .populate("createdBy", "firstName lastName");

    const formatted = tasks.map((task, index) => ({
      sno: index + 1,
      taskId: task._id,
      taskName: task.taskName,
      description: task.description,
      customerName: task.customer?.name || "",
      customerPhone: task.customer?.phone || "",
      service: task.service
        ? {
          _id: task.service._id,
          serviceName: task.service.serviceName,
        }
        : null,
      assignedTo: task.assignedTo
        ? {
          _id: task.assignedTo._id,
          name: `${task.assignedTo.firstName} ${task.assignedTo.lastName}`,
        }
        : null,
      assignedBy: task.assignedBy
        ? {
          _id: task.assignedBy._id,
          name: `${task.assignedBy.firstName} ${task.assignedBy.lastName}`,
        }
        : null,
      createdBy: task.createdBy
        ? {
          _id: task.createdBy._id,
          name: `${task.createdBy.firstName} ${task.createdBy.lastName}`,
        }
        : null,
      createdAt: task.createdAt,
      dueDate: task.dueDate,
      status: task.status,
      priority: task.priority,
    }));

    return res.json({ success: true, data: formatted });
  } catch (err) {
    console.error("Error fetching tasks:", err);
    return errorResponse(res, "Failed to fetch tasks by organization", 500, err);
  }
};

// Get Task By assignTo
const getAgentTask = async (req, res) => {
  try {
    // const orgId = req.params.orgId || req.user?.orgId;
    const agentId = req.params.id;
    const tasks = await Task.find({ assignedTo: agentId, isDeleted: { $ne: true } })
      .sort({ createdAt: -1 })
      .populate("assignedTo", "firstName lastName")
      .populate("service", "serviceName")
      .populate("assignedBy", "firstName lastName")
      .populate("createdBy", "firstName lastName");

    const formatted = tasks.map((task, index) => ({
      sno: index + 1,
      taskId: task._id,
      taskName: task.taskName,
      description: task.description,
      customerName: task.customer?.name || "",
      customerPhone: task.customer?.phone || "",
      serviceName: task.service?.serviceName || "--",
      assignedTo: task.assignedTo
        ? {
          _id: task.assignedTo._id,
          name: `${task.assignedTo.firstName} ${task.assignedTo.lastName}`,
        }
        : null,
      assignedBy: task.assignedBy
        ? {
          _id: task.assignedBy._id,
          name: `${task.assignedBy.firstName} ${task.assignedBy.lastName}`,
        }
        : null,
      createdBy: task.createdBy
        ? {
          _id: task.createdBy._id,
          name: `${task.createdBy.firstName} ${task.createdBy.lastName}`,
        }
        : null,
      createdAt: task.createdAt,
      dueDate: task.dueDate,
      status: task.status,
      priority: task.priority,
    }));

    return res.json({ success: true, data: formatted });
  } catch (err) {
    console.error("Error fetching tasks:", err);
    return errorResponse(res, "Failed to fetch tasks by organization", 500, err);
  }
};


// ------------------ GET OVERDUE TASKS ------------------
const getOverdueTasks = async (req, res) => {
  try {
    const orgId = req.user?.orgId;
    const now = new Date();
    const tasks = await Task.find({ orgId, isDeleted: false, dueDate: { $lt: now }, status: { $ne: "Closed" } }).sort({ dueDate: 1 });
    return res.json({ success: true, data: tasks });
  } catch (err) {
    return errorResponse(res, "Failed to fetch overdue tasks", 500, err);
  }
};

// ------------------ ADD ATTACHMENT ------------------
const addAttachment = async (req, res) => {
  try {
    const { fileName, fileUrl } = req.body;
    const orgId = req.user?.orgId;
    const task = await Task.findOne({ _id: req.params.id, orgId, isDeleted: false });
    if (!task) return errorResponse(res, "Task not found", 404);

    task.attachments.push({ fileName, fileUrl, uploadedAt: new Date() });
    await task.save();

    return res.json({ success: true, message: "Attachment added", data: task });
  } catch (err) {
    return errorResponse(res, "Failed to add attachment", 500, err);
  }
};

// ------------------ ADD COMMENT ------------------
const addComment = async (req, res) => {
  try {
    const { text } = req.body;
    const userId = req.user?._id;
    const orgId = req.user?.orgId;

    const task = await Task.findOne({ _id: req.params.id, orgId, isDeleted: false });
    if (!task) return errorResponse(res, "Task not found", 404);

    task.comments.push({ text, commentedBy: userId, commentedAt: new Date() });
    await task.save();

    return res.json({ success: true, message: "Comment added", data: task });
  } catch (err) {
    return errorResponse(res, "Failed to add comment", 500, err);
  }
};

// ------------------ CREATE NEXT RECURRING TASK ------------------
const createNextRecurringTask = async (req, res) => {
  try {
    const orgId = req.user?.orgId;
    const task = await Task.findOne({ _id: req.params.id, orgId, isDeleted: false });
    if (!task) return errorResponse(res, "Task not found", 404);

    if (!task.recurrence || task.recurrence.type === "None") {
      return errorResponse(res, "Task is not recurring", 400);
    }

    // Calculate next occurrence
    const interval = task.recurrence.interval || 1;
    const nextDate = task.recurrence.nextOccurrence || task.scheduledDate || new Date();
    let newNextDate = new Date(nextDate);

    switch (task.recurrence.type) {
      case "Daily":
        newNextDate.setDate(newNextDate.getDate() + interval);
        break;
      case "Weekly":
        newNextDate.setDate(newNextDate.getDate() + interval * 7);
        break;
      case "Monthly":
        newNextDate.setMonth(newNextDate.getMonth() + interval);
        break;
      default:
        return errorResponse(res, "Invalid recurrence type", 400);
    }

    // Create new task
    const newTask = await Task.create({
      ...task.toObject(),
      _id: undefined,
      createdAt: undefined,
      updatedAt: undefined,
      completedAt: null,
      currentAssignee: null,
      assignedTo: null,
      assignedBy: null,
      isRevoked: false,
      timesReassigned: 0,
      recurrence: { ...task.recurrence, nextOccurrence: null },
      scheduledDate: newNextDate,
      createdBy: req.user?._id,
      updatedBy: req.user?._id,
      taskEvents: [{ type: "Created", details: "Recurring task created", by: req.user?._id, at: new Date() }],
    });

    // Update original task nextOccurrence
    task.recurrence.nextOccurrence = newNextDate;
    await task.save();

    return res.json({ success: true, message: "Next recurring task created", data: newTask });
  } catch (err) {
    return errorResponse(res, "Failed to create next recurring task", 500, err);
  }
};


// ------------------ GET TASK STATS ------------------
// const getTaskStats = async (req, res) => {
//   try {
//     const orgId = req.user.orgId;

//     const stats = await Task.aggregate([
//       {
//         $match: {
//           isDeleted: false,
//           orgId: new mongoose.Types.ObjectId(orgId),
//         },
//       },
//       {
//         $group: {
//           _id: "$status",
//           count: { $sum: 1 },
//         },
//       },
//     ]);

//     const summary = {
//       total: 0,
//       pending: 0,
//       inProgress: 0,
//       overdue: 0,
//       completed: 0,
//       closed: 0,
//     };

//     stats.forEach((item) => {
//       summary.total += item.count;

//       if (item._id === "Pending") summary.pending = item.count;
//       if (item._id === "In Progress") summary.inProgress = item.count;
//       if (item._id === "Overdue") summary.overdue = item.count;
//       if (item._id === "Completed") summary.completed = item.count;
//       if (item._id === "Closed") summary.closed = item.count;
//     });

//     return res.status(200).json({
//       success: true,
//       data: summary,
//     });
//   } catch (err) {
//     console.error("❌ Task Stats Error:", err); // 🔥 LOG REAL ERROR
//     return res.status(500).json({
//       success: false,
//       message: "Failed to fetch task stats",
//     });
//   }
// };


const getTaskStats = async (req, res) => {
  try {
    const orgId = req.user.orgId;

    const now = new Date();

    // Start of today (UTC safe)
    const startOfToday = new Date(now);
    startOfToday.setHours(0, 0, 0, 0);

    // Yesterday
    const startOfYesterday = new Date(startOfToday);
    startOfYesterday.setDate(startOfYesterday.getDate() - 1);

    const endOfYesterday = new Date(startOfToday);
    endOfYesterday.setMilliseconds(-1);

    // Last 7 days (excluding today)
    const startOfLastWeek = new Date(startOfToday);
    startOfLastWeek.setDate(startOfLastWeek.getDate() - 7);

    const baseMatch = {
      isDeleted: false,
      orgId: new mongoose.Types.ObjectId(orgId),
    };

    // 🔹 CURRENT STATS (existing logic)
    const statusStats = await Task.aggregate([
      { $match: baseMatch },
      {
        $group: {
          _id: "$status",
          count: { $sum: 1 },
        },
      },
    ]);

    const summary = {
      total: 0,
      pending: 0,
      inProgress: 0,
      overdue: 0,
      completed: 0,
      closed: 0,
    };

    statusStats.forEach((item) => {
      summary.total += item.count;

      if (item._id === "Pending") summary.pending = item.count;
      if (item._id === "In Progress") summary.inProgress = item.count;
      if (item._id === "Overdue") summary.overdue = item.count;
      if (item._id === "Completed") summary.completed = item.count;
      if (item._id === "Closed") summary.closed = item.count;
    });

    // 🔹 NEW: Yesterday & Last Week stats
    const [yesterdayStats, lastWeekStats] = await Promise.all([
      Task.aggregate([
        {
          $match: {
            ...baseMatch,
            createdAt: { $gte: startOfYesterday, $lte: endOfYesterday },
          },
        },
        {
          $group: {
            _id: "$status",
            count: { $sum: 1 },
          },
        },
      ]),

      Task.aggregate([
        {
          $match: {
            ...baseMatch,
            createdAt: { $gte: startOfLastWeek, $lt: startOfToday },
          },
        },
        {
          $group: {
            _id: "$status",
            count: { $sum: 1 },
          },
        },
      ]),
    ]);

    const yesterday = {
      pending: 0,
      inProgress: 0,
      overdue: 0,
      completed: 0,
      closed: 0,
    };

    yesterdayStats.forEach((item) => {
      if (item._id === "Pending") yesterday.pending = item.count;
      if (item._id === "In Progress") yesterday.inProgress = item.count;
      if (item._id === "Overdue") yesterday.overdue = item.count;
      if (item._id === "Completed") yesterday.completed = item.count;
      if (item._id === "Closed") yesterday.closed = item.count;
    });

    const lastWeek = {
      pending: 0,
      inProgress: 0,
      overdue: 0,
      completed: 0,
      closed: 0,
    };

    lastWeekStats.forEach((item) => {
      if (item._id === "Pending") lastWeek.pending = item.count;
      if (item._id === "In Progress") lastWeek.inProgress = item.count;
      if (item._id === "Overdue") lastWeek.overdue = item.count;
      if (item._id === "Completed") lastWeek.completed = item.count;
      if (item._id === "Closed") lastWeek.closed = item.count;
    });

    return res.status(200).json({
      success: true,
      data: {
        ...summary,   //  existing fields (NO BREAK)
        yesterday,    //  NEW
        lastWeek,     //  NEW
      },
    });
  } catch (err) {
    console.error("❌ Task Stats Error:", err);
    return res.status(500).json({
      success: false,
      message: "Failed to fetch task stats",
    });
  }
};




// const downloadTaskTemplate = async (req, res) => {
//   try {
//     const templateData = [
//       {
//         customerName: "John Doe",
//         customerNumber: "9876543210",
//         service: "AC Repair",
//         priority: "Medium",
//         dueDate: "30-01-2025",
//         assignedToEmail: "agent@email.com",
//         description: "Issue description",
//       },
//     ];

//     const worksheet = XLSX.utils.json_to_sheet(templateData);
//     const workbook = XLSX.utils.book_new();

//     XLSX.utils.book_append_sheet(workbook, worksheet, "Tasks");

//     const buffer = XLSX.write(workbook, {
//       type: "buffer",
//       bookType: "xlsx",
//     });

//     res.setHeader(
//       "Content-Disposition",
//       "attachment; filename=task-bulk-upload-template.xlsx"
//     );
//     res.setHeader(
//       "Content-Type",
//       "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
//     );

//     return res.send(buffer);
//   } catch (err) {
//     console.error("Template download failed:", err);
//     res.status(500).json({ message: "Failed to download template" });
//   }
// };


// const bulkUploadTasks = async (req, res) => {
//   console.log(" BULK UPLOAD API HIT");

//   try {
//     const userId = req.user?._id;
//     const orgId = req.user.orgId;
//     console.log("ADMIN ORG ID:", req.user.orgId);
//     const createdBy = req.user._id;

//     if (!req.file) {
//       return res.status(400).json({
//         success: false,
//         message: "Excel file is required",
//       });
//     }

//     // Read Excel
//     const workbook = XLSX.readFile(req.file.path);
//     const sheet = workbook.Sheets[workbook.SheetNames[0]];
//     const rows = XLSX.utils.sheet_to_json(sheet, { defval: "" });

//     if (!rows.length) {
//       return res.status(400).json({
//         success: false,
//         message: "Excel file is empty",
//       });
//     }

//     const tasksToInsert = [];
//     const errors = [];

//     for (let i = 0; i < rows.length; i++) {
//       const row = rows[i];

//       try {
//         /* ASSIGNEE */
//         const assigneeEmail = row.assignedToEmail?.toString().trim().toLowerCase();

//         const assignee = await User.findOne({
//           email: assigneeEmail,
//           orgId,
//           isDeleted: false,
//         });
//         // console.log("AGENT ORG ID:", assignee?.orgId);

//         if (!assignee) {
//           throw new Error(`Agent not found: ${assigneeEmail}`);
//         }

//         /*  DATE */
//         // let dueDate;

//         // if (typeof row.dueDate === "number") {
//         //   // Excel serial date
//         //   dueDate = new Date(Math.round((row.dueDate - 25569) * 86400 * 1000));
//         // } else {
//         //   const [day, month, year] = row.dueDate.split("-");
//         //   dueDate = new Date(`${year}-${month}-${day}`);
//         // }

//         // if (isNaN(dueDate.getTime())) {
//         //   throw new Error(`Invalid dueDate: ${row.dueDate}`);
//         // }

//         /* PRIORITY  */
//         const priorityMap = {
//           low: "Low",
//           medium: "Medium",
//           high: "High",
//           critical: "Critical",
//         };

//         const priority =
//           priorityMap[row.priority?.toString().toLowerCase()] || "Medium";

//         /* DUPLICATE CHECK (INDUSTRY LEVEL) */
//         // const isDuplicate = await Task.exists({
//         //   orgId,
//         //   "customer.phone": String(row.customerNumber || ""),
//         //   service: row.service || "",
//         //   assignedTo: assignee._id,
//         //   isDeleted: false,
//         // });

//         // if (isDuplicate) {
//         //   throw new Error(
//         //     `Duplicate task already exists for customer ${row.customerNumber}`
//         //   );
//         // }


//         /* TASK  */
//         tasksToInsert.push({
//           taskName: `TASK-${Date.now()}-${i}`,
//           description: row.description || "",

//           customer: {
//             name: row.customerName || "",
//             phone: String(row.customerNumber || ""),
//           },

//           dueDate: null,
//           priority,
//           status: "Pending",

//           assignedTo: assignee._id,
//           assignedBy: createdBy,

//           assignmentHistory: [
//             {
//               assignedTo: assignee._id,
//               assignedBy: createdBy,
//               assignedAt: new Date(),
//               previousStatus: "Pending",
//             },
//           ],

//           taskEvents: [
//             {
//               type: "Created",
//               details: "Task created via Excel upload",
//               by: createdBy,
//             },
//           ],

//           orgId,
//           createdBy,
//           updatedBy: createdBy,
//         });
//       } catch (err) {
//         errors.push({
//           row: i + 2, // Excel row number
//           error: err.message,
//         });
//       }
//     }

//     /* INSERT */
//     if (tasksToInsert.length > 0) {
//       console.log(" READY TO INSERT:", tasksToInsert.length);
//       console.log(" SAMPLE TASK:", tasksToInsert[0]);

//       await Task.insertMany(tasksToInsert);
//     }

//     return res.status(201).json({
//       success: true,
//       inserted: tasksToInsert.length,
//       failed: errors.length,
//       errors,
//     });
//   } catch (err) {
//     console.error("❌ BULK UPLOAD FAILED:", err);
//     return res.status(500).json({
//       success: false,
//       message: "Bulk upload failed",
//     });
//   }
// };

const bulkUploadTasks = async (req, res) => {
  console.log("BULK UPLOAD TASKS API HIT");
  try {
    const orgId = req.user.orgId;
    const createdBy = req.user._id;

    //  File validation
    if (!req.file) {
      return res.status(400).json({
        success: false,
        message: "Excel file is required",
      });
    }

    // Read Excel
    const workbook = XLSX.readFile(req.file.path);
    const sheet = workbook.Sheets[workbook.SheetNames[0]];
    const rows = XLSX.utils.sheet_to_json(sheet, { defval: "" });

    if (!rows.length) {
      return res.status(400).json({
        success: false,
        message: "Excel file is empty",
      });
    }

    const tasksToInsert = [];
    const errors = [];

    // Priority normalization
    const priorityMap = {
      low: "Low",
      medium: "Medium",
      high: "High",
      critical: "Critical",
    };

    //  Process rows
    for (let i = 0; i < rows.length; i++) {
      const row = rows[i];

      try {
        // Required validations
        if (!row.customerName || !row.customerNumber) {
          throw new Error("Customer name and number are required");
        }

        // duplicate found
        // if (isDuplicate) {
        //   // Optional: log skipped row
        //   errors.push({
        //     row: i + 2,
        //     error: `Duplicate task skipped for ${customerPhone} (${service})`,
        //   });
        //   continue; // 🔥 skip this row
        // }

        const priority =
          priorityMap[row.priority?.toString().toLowerCase()] || "Medium";

        tasksToInsert.push({
          taskName: `TASK-${Date.now()}-${i}`,
          description: row.description || "",

          customer: {
            name: row.customerName.trim(),
            phone: String(row.customerNumber).trim(),
          },

          // Assignment handled later via UI
          assignedTo: null,
          assignedBy: null,
          isAssigned: false,

          dueDate: null,
          priority,
          status: "Pending",

          assignmentHistory: [],

          taskEvents: [
            {
              type: "Created",
              details: "Task created via Excel upload",
              by: createdBy,
            },
          ],

          orgId,
          createdBy,
          updatedBy: createdBy,
        });
      } catch (err) {
        errors.push({
          row: i + 2, // Excel row index
          error: err.message,
        });
      }
    }

    //  Insert valid rows
    if (tasksToInsert.length > 0) {
      await Task.insertMany(tasksToInsert);
    }

    return res.status(201).json({
      success: true,
      inserted: tasksToInsert.length,
      failed: errors.length,
      errors,
    });
  } catch (err) {
    console.error("BULK UPLOAD FAILED:", err);
    return res.status(500).json({
      success: false,
      message: "Bulk upload failed",
    });
  }
};

// const exportTasksExcel = async (req, res) => {
//   try {
//     const orgId = req.user.orgId;

//     const tasks = await Task.find({ orgId, isDeleted: false })
//       .populate("assignedTo", "email")
//       .lean();

//     if (!tasks.length) {
//       return res.status(404).json({
//         success: false,
//         message: "No tasks found to export",
//       });
//     }

//     const excelData = tasks.map((task) => ({
//       customerName: task.customer?.name || "",
//       customerNumber: task.customer?.phone || "",
//       priority: task.priority,
//       status: task.status,
//       assignedToEmail: task.assignedTo?.email || "",
//       dueDate: task.dueDate
//         ? new Date(task.dueDate).toLocaleDateString("en-GB")
//         : "",
//       description: task.description || "",
//     }));

//     const worksheet = XLSX.utils.json_to_sheet(excelData);
//     const workbook = XLSX.utils.book_new();
//     XLSX.utils.book_append_sheet(workbook, worksheet, "Tasks");

//     const buffer = XLSX.write(workbook, {
//       type: "buffer",
//       bookType: "xlsx",
//     });

//     res.setHeader(
//       "Content-Disposition",
//       "attachment; filename=tasks-export.xlsx"
//     );
//     res.setHeader(
//       "Content-Type",
//       "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
//     );

//     return res.send(buffer);
//   } catch (err) {
//     console.error("EXPORT FAILED:", err);
//     return res.status(500).json({
//       success: false,
//       message: "Export failed",
//     });
//   }
// };

const exportTasksExcel = async (req, res) => {
  try {
    const orgId = req.user.orgId;

    const tasks = await Task.find({ orgId, isDeleted: false })
      .populate("assignedTo", "firstName lastName")
      .populate("assignedBy", "firstName lastName")
      .sort({ createdAt: -1 })
      .lean();

    if (!tasks.length) {
      return res.status(404).json({
        success: false,
        message: "No tasks found to export",
      });
    }

    const excelData = tasks.map((task, index) => ({
      sno: index + 1,
      // taskId: task._id.toString(),
      customerName: task.customer?.name || "",
      customerNumber: task.customer?.phone || "",
      assignedTo: task.assignedTo
        ? `${task.assignedTo.firstName} ${task.assignedTo.lastName}`
        : "Unassigned",
      assignedDate: task.createdAt
        ? new Date(task.createdAt).toLocaleDateString("en-GB")
        : "",
      dueDate: task.dueDate
        ? new Date(task.dueDate).toLocaleDateString("en-GB")
        : "",
      priority: task.priority,
      status: task.status,
      description: task.description || "",
    }));

    const worksheet = XLSX.utils.json_to_sheet(excelData);
    const workbook = XLSX.utils.book_new();
    XLSX.utils.book_append_sheet(workbook, worksheet, "Tasks");

    const buffer = XLSX.write(workbook, {
      type: "buffer",
      bookType: "xlsx",
    });

    res.setHeader(
      "Content-Disposition",
      "attachment; filename=tasks-export.xlsx"
    );
    res.setHeader(
      "Content-Type",
      "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
    );

    return res.send(buffer);
  } catch (err) {
    console.error("EXPORT FAILED:", err);
    return res.status(500).json({
      success: false,
      message: "Export failed",
    });
  }
};






module.exports = {
  getTasksByAssignee,
  getTasksByOrg,
  getOverdueTasks,
  addAttachment,
  addComment,
  createNextRecurringTask,
  createTask,
  getTaskById,
  getTasks,
  updateTask,
  deleteTask,
  assignTask,
  reassignTask,
  revokeTask,
  getAgentTask,
  // downloadTaskTemplate,
  bulkUploadTasks,
  exportTasksExcel,
  getTaskStats,
  // getTaskStats
  // createTaskOne,
  // getTaskByIdOne,
};
