import prisma from '../lib/prisma';
import { getIO } from '../socket';
import { SOCKET_EVENTS } from '@ehandyhire/shared';
import { NotificationType } from '@prisma/client';
import { buildSimpleEmailHtml, sendEmail } from './email.service';

const APP_URL = (process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000').replace(/\/$/, '');

export async function createAndEmitNotification(
  userId: string,
  type: NotificationType,
  title: string,
  message: string,
  data?: Record<string, unknown>
) {
  const notification = await prisma.notification.create({
    data: {
      userId,
      type,
      title,
      message,
      data: data ? (data as object) : undefined,
    },
  });

  try {
    const io = getIO();
    io.to(`user:${userId}`).emit(SOCKET_EVENTS.NOTIFICATION, notification);
  } catch (e) {
    console.error('Failed to emit notification:', e);
  }

  return notification;
}

type NotifyUserOptions = {
  userId: string;
  type: NotificationType;
  title: string;
  message: string;
  data?: Record<string, unknown>;
  /** Also email the user when they have an email address. Default true. */
  email?: boolean;
  emailSubject?: string;
  ctaLabel?: string;
  ctaPath?: string;
};

/**
 * In-app notification + optional email (best-effort; email failures do not throw).
 */
export async function notifyUser({
  userId,
  type,
  title,
  message,
  data,
  email = true,
  emailSubject,
  ctaLabel,
  ctaPath,
}: NotifyUserOptions) {
  const notification = await createAndEmitNotification(userId, type, title, message, data);

  if (email) {
    const user = await prisma.user.findUnique({
      where: { id: userId },
      select: { email: true, firstName: true },
    });
    if (user?.email) {
      const ctaUrl = ctaPath ? `${APP_URL}${ctaPath.startsWith('/') ? '' : '/'}${ctaPath}` : undefined;
      const greeting = user.firstName ? `Hi ${user.firstName},\n\n` : '';
      const text = `${greeting}${message}${ctaUrl ? `\n\n${ctaLabel || 'Open'}: ${ctaUrl}` : ''}`;
      await sendEmail({
        to: user.email,
        subject: emailSubject || title,
        text,
        html: buildSimpleEmailHtml({
          title,
          body: `${greeting}${message}`,
          ctaLabel: ctaLabel,
          ctaUrl,
        }),
        throwOnError: false,
      });
    }
  }

  return notification;
}

export async function getConversationRecipientIds(conversationId: string, excludeUserId: string) {
  const conversation = await prisma.conversation.findUnique({
    where: { id: conversationId },
    include: {
      job: {
        select: {
          id: true,
          customerId: true,
          worker: { select: { userId: true } },
          quotations: { select: { worker: { select: { userId: true } } } },
        },
      },
      contextWorker: { select: { userId: true } },
      customer: { select: { id: true } },
      messages: {
        select: { senderId: true },
        distinct: ['senderId'],
      },
    },
  });

  const recipientIds = new Set<string>();
  if (conversation?.job?.customerId) recipientIds.add(conversation.job.customerId);
  if (conversation?.job?.worker?.userId) recipientIds.add(conversation.job.worker.userId);
  conversation?.job?.quotations.forEach((q) => {
    if (q.worker.userId) recipientIds.add(q.worker.userId);
  });
  if (conversation?.customerId) recipientIds.add(conversation.customerId);
  if (conversation?.contextWorker?.userId) recipientIds.add(conversation.contextWorker.userId);
  conversation?.messages.forEach((m) => recipientIds.add(m.senderId));
  recipientIds.delete(excludeUserId);

  return {
    recipientIds: Array.from(recipientIds),
    job: conversation?.job,
  };
}

export async function notifyNewMessage(
  conversationId: string,
  senderId: string,
  senderName: string,
  content: string
) {
  const { recipientIds, job } = await getConversationRecipientIds(conversationId, senderId);
  const preview = content.length > 80 ? `${content.slice(0, 80)}...` : content;

  await Promise.all(
    recipientIds.map((userId) =>
      createAndEmitNotification(
        userId,
        'MESSAGE_RECEIVED',
        `Message from ${senderName}`,
        preview,
        { conversationId, jobId: job?.id || null }
      )
    )
  );
}
