import dayjs from 'dayjs';
import utc from 'dayjs/plugin/utc';
import timezone from 'dayjs/plugin/timezone';
dayjs.extend(utc);
dayjs.extend(timezone);

import {
  NotificationStatus,
  NotificationType,
  UserType,
} from '@/modules/notification/notification.constant';
import { createNotification } from '@/modules/notification/notification.service';
import { getObjectId } from '@/shared/utils/commonHelper';
import { TaskStatus } from '@/modules/tasks/tasks.constant';
import { Tasks } from '@/modules/tasks/tasks.model';
import { Activity } from '@/modules/activity/activity.model';
import { ActivityRemainder } from '@/modules/activity/activityRemainder/activityRemainder.model';
import { ActivityStatus } from '@/shared/constants/enum.constant';

export const markOverdueTasks = async () => {
  const now = new Date();

  // Find task IDs that will become overdue
  const overdueTasks = await Tasks.find(
    {
      activityDate: { $lt: now },
      status: { $nin: [TaskStatus.COMPLETED, TaskStatus.OVERDUE] },
    },
    { _id: 1 },
  ).lean();

  const taskIds = overdueTasks.map((t) => t._id);

  if (taskIds.length === 0) {
    console.log('No tasks to mark as overdue');
    return;
  }

  // Mark tasks as overdue
  const result = await Tasks.updateMany(
    { _id: { $in: taskIds } },
    { $set: { status: TaskStatus.OVERDUE } },
  );

  // console.log(`${taskIds} Marked ${result.modifiedCount} tasks as overdue`);

  // Step 3: Find linked activities and mark them as overdue
  const overdueActivities = await Activity.find(
    {
      task: { $in: taskIds },
      status: ActivityStatus.PENDING,
    },
    { _id: 1 },
  ).lean();

  const activityIds = overdueActivities.map((a) => a._id);

  if (activityIds.length > 0) {
    await Activity.updateMany(
      { _id: { $in: activityIds } },
      { $set: { status: ActivityStatus.OVERDUE } },
    );  // console.log(`${activityIds} Marked ${activityIds.length} linked activities as overdue`);

    // Step 4: Update linked ActivityRemainders to overdue
    await ActivityRemainder.updateMany(
      { activityId: { $in: activityIds }, status: { $ne: ActivityStatus.COMPLETED } },
      { $set: { status: ActivityStatus.OVERDUE } },
    );
    // console.log('Updated linked activity remainders to overdue');
  }
};

/**
 * Fetch tasks not completed and having notifyAt near current time (±1 min)
 */
const fetchTasksToNotify = async () => {
  const now = dayjs().tz('Asia/Kolkata');

  const startWindow = now.subtract(1, 'minute').format();
  const endWindow = now.add(1, 'minute').format();

  const tasks = await Tasks.find({
    status: { $ne: TaskStatus.COMPLETED },
    notifyAt: { $elemMatch: { $gte: endWindow, $lte: startWindow } },
  }).lean();

  return tasks;
};

/**
 * Send notification for a single task based on matched notifyAt time
 * Supports 30 mins before, due now, 15 mins overdue notifications
 */
const sendNotificationForTask = async (task) => {
  const now = dayjs();
  const activityDate = dayjs(task.activityDate);
  const notifyTimes = (task.notifyAt || []).map((dt) => dayjs(dt));
  const matchedNotify = notifyTimes.find((nt) => nt.isSame(now, 'minute'));

  if (!matchedNotify && !activityDate.isSame(now, 'minute')) return;

  let title = '';
  let description = '';

  const activityType = task.activityType || 'task';
  const leadName = task.leadId?.contactDetails?.name || 'Lead';

  if (matchedNotify) {
    const diffMins = matchedNotify.diff(activityDate, 'minute');
    if (diffMins === -30) {
      title = `Upcoming ${activityType || task.activity_type} at ${activityDate.format('h:mm A')}`;
      description = `Your ${activityType || task.activity_type} with ${leadName} starts in 30 minutes.`;
    } else if (diffMins === 15) {
      title = `Overdue ${activityType || task.activity_type}`;
      description = `Your ${activityType || task.activity_type} for ${leadName} was scheduled at ${activityDate.format(
        'h:mm A',
      )}. Please update the status.`;
    } else {
      title = `${activityType || task.activity_type} Reminder`;
      description = `Reminder for your ${activityType || task.activity_type} with ${leadName}.`;
    }
  } else if (activityDate.isSame(now, 'minute')) {
    title = `${activityType || task.activity_type} Due Now`;
    description = `Your ${activityType || task.activity_type} for ${leadName} is due now.`;
  }

  const appRedirect = {
    screenType: 'Task_Details',
    id: task._id,
  };

  await createNotification(
    {
      title,
      description,
      userType: UserType.SELF,
      user: getObjectId(task.assignedTo),
      status: NotificationStatus.SEND,
      notificationType: NotificationType.ALERT,
    },
    appRedirect,
  );
};

/**
 * Entry point: check tasks for notification and send
 */
export const processTaskRemainder = async () => {
  const tasksToNotify = await fetchTasksToNotify();

  await Promise.all(tasksToNotify.map(sendNotificationForTask));
};
