const mongoose = require('mongoose');
const { createProviderRegistryForTenant } = require('@/services/integrations/providerRegistry');

const sanitizeMessage = (message = '') => String(message).replace(/\s+/g, ' ').trim().slice(0, 500);

const shouldSendEvent = ({ preferences, type, channel }) => {
  if (!preferences) return channel === 'in_app' ? true : false;
  const byType = preferences.eventPreferences?.[type];
  if (byType && typeof byType[channel] === 'boolean') return byType[channel];
  if (channel === 'in_app') return preferences.inApp !== false;
  if (channel === 'email') return preferences.email !== false;
  if (channel === 'whatsapp') return preferences.whatsapp === true;
  return false;
};

const loadPreferences = async ({ tenantId, recipientId }) =>
  mongoose.model('NotificationPreference').findOne({ tenant: tenantId, admin: recipientId, removed: false }).lean();

const deliverEmail = async ({ providers, recipient, notification }) => {
  if (!recipient?.email) return { status: 'skipped', message: 'Recipient email unavailable' };
  const result = await providers.resend.sendEmail({
    to: recipient.email,
    subject: notification.title,
    html: `<p>${notification.message}</p>${notification.actionUrl ? `<p><a href="${notification.actionUrl}">Open in IDURAR</a></p>` : ''}`,
  });
  return { status: result?.disabled ? 'skipped' : 'delivered', message: result?.message || '' };
};

const deliverWhatsApp = async ({ providers, recipient, notification }) => {
  const phone = recipient?.phone || recipient?.whatsappNumber;
  if (!phone) return { status: 'skipped', message: 'Recipient WhatsApp number unavailable' };
  const result = await providers.meta.request('sendWhatsApp', {
    messaging_product: 'whatsapp',
    to: phone,
    type: 'text',
    text: { body: `${notification.title}\n${notification.message}`.slice(0, 1024) },
  });
  return { status: result?.disabled ? 'skipped' : 'delivered', message: result?.message || '' };
};

const createNotification = async ({
  tenantId,
  actorId,
  recipientId,
  type,
  title,
  message,
  severity = 'info',
  entityType,
  entityId,
  actionUrl,
  eventKey,
  channels = ['in_app'],
  expiresAt,
}) => {
  if (!mongoose.models.Notification || !mongoose.models.Admin || !mongoose.models.NotificationPreference) {
    return null;
  }
  const Notification = mongoose.model('Notification');
  const Admin = mongoose.model('Admin');
  const payload = {
    tenant: tenantId,
    createdBy: actorId,
    assignedTo: recipientId,
    recipient: recipientId,
    type,
    title,
    message: sanitizeMessage(message),
    severity,
    entityType,
    entityId,
    actionUrl,
    eventKey,
    channels,
    deliveredAt: new Date(),
    deliveryStatus: { inApp: 'delivered', email: 'skipped', whatsapp: 'skipped' },
    expiresAt,
  };

  let notification;
  if (eventKey) {
    notification = await Notification.findOneAndUpdate(
      { tenant: tenantId, recipient: recipientId, eventKey },
      { $setOnInsert: payload },
      { upsert: true, new: true, setDefaultsOnInsert: true }
    );
  } else {
    notification = await Notification.create(payload);
  }

  const recipient = await Admin.findById(recipientId).lean();
  const preferences = await loadPreferences({ tenantId, recipientId });
  const providers = await createProviderRegistryForTenant({ tenantId });
  const deliveryLog = [];

  if (channels.includes('email') && shouldSendEvent({ preferences, type, channel: 'email' })) {
    try {
      const result = await deliverEmail({ providers, recipient, notification });
      notification.deliveryStatus.email = result.status;
      deliveryLog.push({ channel: 'email', status: result.status, message: result.message, deliveredAt: new Date() });
    } catch (error) {
      notification.deliveryStatus.email = 'failed';
      deliveryLog.push({ channel: 'email', status: 'failed', message: error.message, deliveredAt: new Date() });
    }
  }

  if (channels.includes('whatsapp') && shouldSendEvent({ preferences, type, channel: 'whatsapp' })) {
    try {
      const result = await deliverWhatsApp({ providers, recipient, notification });
      notification.deliveryStatus.whatsapp = result.status;
      deliveryLog.push({ channel: 'whatsapp', status: result.status, message: result.message, deliveredAt: new Date() });
    } catch (error) {
      notification.deliveryStatus.whatsapp = 'failed';
      deliveryLog.push({ channel: 'whatsapp', status: 'failed', message: error.message, deliveredAt: new Date() });
    }
  }

  notification.deliveryLog = [...(notification.deliveryLog || []), ...deliveryLog];
  await notification.save();
  return notification;
};

const listNotifications = async ({ tenantId, recipientId, unreadOnly = false, limit = 50 }) =>
  mongoose.model('Notification')
    .find({
      tenant: tenantId,
      recipient: recipientId,
      removed: false,
      ...(unreadOnly ? { readAt: { $exists: false } } : {}),
    })
    .sort({ created: -1 })
    .limit(limit)
    .lean();

const unreadCount = async ({ tenantId, recipientId }) =>
  mongoose.model('Notification').countDocuments({
    tenant: tenantId,
    recipient: recipientId,
    removed: false,
    readAt: { $exists: false },
  });

module.exports = {
  createNotification,
  listNotifications,
  unreadCount,
};
