/**
 * Task Controller
 * Handles task management operations
 */

const Task = require("../models/Task");
const Employee = require("../models/Employee");
const User = require("../models/User");
const ActivityLog = require("../models/ActivityLog");
const Notification = require("../models/Notification");
const { query } = require("../config/database");

/**
 * Get all tasks
 * GET /api/tasks
 */
const getAllTasks = async (req, res, next) => {
  try {
    const {
      page,
      limit,
      search,
      status,
      priority,
      assignedTo,
      departmentId,
      startDate,
      endDate,
      sortBy,
      sortOrder,
    } = req.query;

    const result = await Task.findAll({
      page: parseInt(page) || 1,
      limit: parseInt(limit) || 10,
      search,
      status,
      priority,
      assignedTo,
      departmentId,
      startDate,
      endDate,
      sortBy,
      sortOrder,
    });

    res.json({
      success: true,
      data: result.tasks,
      pagination: result.pagination,
    });
  } catch (error) {
    next(error);
  }
};

/**
 * Get task by ID
 * GET /api/tasks/:id
 */
const getTaskById = async (req, res, next) => {
  try {
    const task = await Task.findById(req.params.id);

    if (!task) {
      return res.status(404).json({
        success: false,
        message: "Task not found",
      });
    }

    res.json({
      success: true,
      data: task,
    });
  } catch (error) {
    next(error);
  }
};

/**
 * Create new task
 * POST /api/tasks
 */
const createTask = async (req, res, next) => {
  try {
    const {
      title,
      description,
      assignedTo,
      departmentId,
      priority,
      startDate,
      dueDate,
      estimatedHours,
    } = req.body;

    // Get assigning user's employee ID
    const assigningUser = await User.findById(req.user.id);

    const task = await Task.create({
      title,
      description,
      assignedTo,
      assignedBy: assigningUser.employee_id,
      departmentId,
      priority,
      startDate,
      dueDate,
      estimatedHours,
    });

    // Create notification for assigned employee
    if (assignedTo) {
      const assignedEmployee = await Employee.findById(assignedTo);
      if (assignedEmployee && assignedEmployee.user_id) {
        await Notification.create({
          userId: assignedEmployee.user_id,
          title: "New Task Assigned",
          message: `You have been assigned a new task: ${title}`,
          type: "Task",
          referenceType: "Task",
          referenceId: task.id,
        });
      }
    }

    // Log activity
    await ActivityLog.create({
      userId: req.user.id,
      actionType: "CREATE",
      entityType: "Task",
      entityId: task.id,
      description: `Created task: ${title}`,
      newValues: task,
      ipAddress: req.ip,
      userAgent: req.headers["user-agent"],
    });

    const createdTask = await Task.findById(task.id);

    res.status(201).json({
      success: true,
      message: "Task created successfully",
      data: createdTask,
    });
  } catch (error) {
    next(error);
  }
};

/**
 * Update task
 * PUT /api/tasks/:id
 */
const updateTask = async (req, res, next) => {
  try {
    const { id } = req.params;

    const existingTask = await Task.findById(id);

    if (!existingTask) {
      return res.status(404).json({
        success: false,
        message: "Task not found",
      });
    }

    const updatedTask = await Task.update(id, req.body);

    // Create notification if assignee changed
    if (
      req.body.assignedTo &&
      req.body.assignedTo !== existingTask.assigned_to
    ) {
      const newAssignee = await Employee.findById(req.body.assignedTo);
      if (newAssignee && newAssignee.user_id) {
        await Notification.create({
          userId: newAssignee.user_id,
          title: "Task Assigned",
          message: `You have been assigned to task: ${updatedTask.title}`,
          type: "Task",
          referenceType: "Task",
          referenceId: id,
        });
      }
    }

    // Log activity
    await ActivityLog.create({
      userId: req.user.id,
      actionType: "UPDATE",
      entityType: "Task",
      entityId: id,
      description: `Updated task: ${updatedTask.title}`,
      oldValues: existingTask,
      newValues: updatedTask,
      ipAddress: req.ip,
      userAgent: req.headers["user-agent"],
    });

    res.json({
      success: true,
      message: "Task updated successfully",
      data: updatedTask,
    });
  } catch (error) {
    next(error);
  }
};

/**
 * Update task status
 * PATCH /api/tasks/:id/status
 */
const updateTaskStatus = async (req, res, next) => {
  try {
    const { id } = req.params;
    const { status } = req.body;

    const existingTask = await Task.findById(id);

    if (!existingTask) {
      return res.status(404).json({
        success: false,
        message: "Task not found",
      });
    }

    // Check if employee is authorized to update (must be assigned to this task)
    if (req.user.role === "Employee") {
      const employee = await Employee.findById(req.user.employeeId);
      if (!employee || existingTask.assigned_to !== employee.id) {
        return res.status(403).json({
          success: false,
          message: "Not authorized to update this task",
        });
      }
    }

    const updatedTask = await Task.updateStatus(id, status);

    // Create notification for task completion
    if (status === "Completed" && existingTask.assigned_by) {
      const assigner = await Employee.findById(existingTask.assigned_by);
      if (assigner && assigner.user_id) {
        await Notification.create({
          userId: assigner.user_id,
          title: "Task Completed",
          message: `Task "${updatedTask.title}" has been completed`,
          type: "Task",
          referenceType: "Task",
          referenceId: id,
        });
      }
    }

    // Log activity
    await ActivityLog.create({
      userId: req.user.id,
      actionType: "STATUS_UPDATE",
      entityType: "Task",
      entityId: id,
      description: `Task status changed from ${existingTask.status} to ${status}`,
      oldValues: { status: existingTask.status },
      newValues: { status },
      ipAddress: req.ip,
      userAgent: req.headers["user-agent"],
    });

    res.json({
      success: true,
      message: "Task status updated successfully",
      data: updatedTask,
    });
  } catch (error) {
    next(error);
  }
};

/**
 * Delete task
 * DELETE /api/tasks/:id
 */
const deleteTask = async (req, res, next) => {
  try {
    const { id } = req.params;

    const task = await Task.findById(id);

    if (!task) {
      return res.status(404).json({
        success: false,
        message: "Task not found",
      });
    }

    await Task.softDelete(id);

    // Log activity
    await ActivityLog.create({
      userId: req.user.id,
      actionType: "DELETE",
      entityType: "Task",
      entityId: id,
      description: `Deleted task: ${task.title}`,
      oldValues: task,
      ipAddress: req.ip,
      userAgent: req.headers["user-agent"],
    });

    res.json({
      success: true,
      message: "Task deleted successfully",
    });
  } catch (error) {
    next(error);
  }
};

/**
 * Get my tasks (for current employee)
 * GET /api/tasks/my-tasks
 */
const getMyTasks = async (req, res, next) => {
  try {
    const { status } = req.query;

    const tasks = await Task.findByEmployee(req.user.employeeId, { status });

    res.json({
      success: true,
      data: tasks,
    });
  } catch (error) {
    next(error);
  }
};

/**
 * Get task statistics
 * GET /api/tasks/statistics
 */
const getTaskStatistics = async (req, res, next) => {
  try {
    const { employeeId } = req.query;

    let statsEmployeeId = null;

    // If employee, only show their stats
    if (req.user.role === "Employee") {
      statsEmployeeId = req.user.employeeId;
    } else if (employeeId) {
      statsEmployeeId = employeeId;
    }

    const stats = await Task.getStatistics(statsEmployeeId);

    res.json({
      success: true,
      data: stats,
    });
  } catch (error) {
    next(error);
  }
};

/**
 * Get overdue tasks
 * GET /api/tasks/overdue
 */
const getOverdueTasks = async (req, res, next) => {
  try {
    const { limit } = req.query;

    const tasks = await Task.getOverdueTasks(parseInt(limit) || 10);

    res.json({
      success: true,
      data: tasks,
    });
  } catch (error) {
    next(error);
  }
};

/**
 * Get upcoming deadlines
 * GET /api/tasks/upcoming
 */
const getUpcomingDeadlines = async (req, res, next) => {
  try {
    const { days } = req.query;

    let employeeId = null;
    if (req.user.role === "Employee") {
      employeeId = req.user.employeeId;
    }

    const tasks = await Task.getUpcomingDeadlines(
      parseInt(days) || 7,
      employeeId,
    );

    res.json({
      success: true,
      data: tasks,
    });
  } catch (error) {
    next(error);
  }
};

module.exports = {
  getAllTasks,
  getTaskById,
  createTask,
  updateTask,
  updateTaskStatus,
  deleteTask,
  getMyTasks,
  getTaskStatistics,
  getOverdueTasks,
  getUpcomingDeadlines,
};
