import User from '@/modules/user/user.model';
import { sendFCMNotification } from '../pushNotification/firebaseNotification.service';
import { createPushNotification } from '../pushNotification/pushNotification.service';
import { NotificationDevice, UserType } from './notification.constant';
import { Types } from 'mongoose';
import { getObjectId } from '@/shared/utils/commonHelper';
import { IUserDoc } from '../user/user.interfaces';
import { NotificationAppRedirect } from './notification.interface';

interface NotificationPayload {
  title?: string;
  description?: string;
  image?: string;
  userType?: UserType;
  user?: Types.ObjectId; // If this exists → send only to this user
  users?: Types.ObjectId[];
  device?: NotificationDevice;
  createdBy?: Types.ObjectId;
}

interface PopulatedCompany {
  companyType: UserType.BUILDER | UserType.BROKER;
}

export const sendNotificationToUsers = async (
  notification: NotificationPayload & { notificationType?: string },
  appRedirect?: NotificationAppRedirect,
): Promise<void> => {
  const {
    title,
    description,
    image,
    userType,
    device,
    createdBy,
    user,
    users,
  } = notification;

  const sendToUser = async (userDoc) => {
    const tokens = userDoc.deviceToken ?? [];
    if (typeof tokens !== 'object' || tokens.length === 0) return;

    await createPushNotification({
      title: title!,
      description: description!,
      image,
      type: 'notification',
      receivedTo: getObjectId(userDoc._id as string),
      createdBy,
      appRedirect: {
        screenType: appRedirect?.screenType,
        screenId: appRedirect?.id,
        unitId: appRedirect?.unitId || null,
        unitNumber: appRedirect?.unitNumber || null,
      },
    });

    await Promise.all(
      tokens.map((token) =>
        sendFCMNotification({
          token,
          title,
          body: description,
          imageUrl: image,
          data: {
            notificationType: 'notification',
            screenType: appRedirect?.screenType,
            screenId: appRedirect?.id,
            unitId: appRedirect?.unitId || null,
            unitNumber: appRedirect?.unitNumber || null,
            type: notification.notificationType,
          },
        }),
      ),
    );
  };

  // CASE 1: Multiple specific users
  if (users && users.length > 0) {
    const multipleUsers = await User.find({ _id: { $in: users } })
      .select('deviceToken')
      .lean();
    await Promise.all(multipleUsers.map(sendToUser));
    return;
  }

  // CASE 2: Send to a single user if user id is provided
  if (user) {
    const singleUser = await User.findById(user).select('deviceToken').lean();
    if (singleUser) await sendToUser(singleUser as unknown as IUserDoc);

    return;
  }

  // CASE 3: Send to multiple users filtered by device and userType criteria
  const deviceTypeFilter =
    device === NotificationDevice.ALL ? { $exists: true } : device;

  let allUsers = await User.find(
    {
      deviceType: deviceTypeFilter,
      deviceToken: { $exists: true, $ne: [] },
      'company.id': { $exists: true, $ne: null },
    },
    { deviceToken: 1, company: 1 },
  )
    .populate({
      path: 'company.id',
      select: 'companyType',
    })
    .lean();

  if (userType !== UserType.ALL)
    allUsers = allUsers.filter((u) => {
      const company = u.company?.id;
      if (company && typeof company === 'object' && 'companyType' in company)
        return (company as PopulatedCompany).companyType === userType;

      return false;
    });

  await Promise.allSettled(allUsers.map(sendToUser));
};
