/**
 * Unified Notification Service
 *
 * Handles sending notifications via multiple channels:
 * - Email (via nodemailer)
 * - WhatsApp (via Meta or Twilio)
 */

import { prisma } from '@/lib/prisma'
import {
  sendMagicLinkEmail,
  sendJuryInvitationEmail,
  sendEvaluationReminderEmail,
  sendAnnouncementEmail,
} from '@/lib/email'
import { getWhatsAppProvider, getWhatsAppProviderType } from '@/lib/whatsapp'
import type { NotificationChannel } from '@prisma/client'

export type NotificationType =
  | 'MAGIC_LINK'
  | 'JURY_INVITATION'
  | 'EVALUATION_REMINDER'
  | 'ANNOUNCEMENT'

interface NotificationResult {
  success: boolean
  channels: {
    email?: { success: boolean; error?: string }
    whatsapp?: { success: boolean; messageId?: string; error?: string }
  }
}

/**
 * Send a notification to a user based on their preferences
 */
export async function sendNotification(
  userId: string,
  type: NotificationType,
  data: Record<string, string>
): Promise<NotificationResult> {
  // Get user with notification preferences
  const user = await prisma.user.findUnique({
    where: { id: userId },
    select: {
      id: true,
      email: true,
      name: true,
      phoneNumber: true,
      notificationPreference: true,
      whatsappOptIn: true,
    },
  })

  if (!user) {
    return {
      success: false,
      channels: {},
    }
  }

  const result: NotificationResult = {
    success: true,
    channels: {},
  }

  const preference = user.notificationPreference

  // Determine which channels to use
  const sendEmail = preference === 'EMAIL' || preference === 'BOTH'
  const sendWhatsApp =
    (preference === 'WHATSAPP' || preference === 'BOTH') &&
    user.whatsappOptIn &&
    user.phoneNumber

  // Send via email
  if (sendEmail) {
    const emailResult = await sendEmailNotification(user.email, user.name, type, data)
    result.channels.email = emailResult

    // Log the notification
    await logNotification(user.id, 'EMAIL', 'SMTP', type, emailResult)
  }

  // Send via WhatsApp
  if (sendWhatsApp && user.phoneNumber) {
    const whatsappResult = await sendWhatsAppNotification(
      user.phoneNumber,
      user.name,
      type,
      data
    )
    result.channels.whatsapp = whatsappResult

    // Log the notification
    const providerType = await getWhatsAppProviderType()
    await logNotification(
      user.id,
      'WHATSAPP',
      providerType || 'UNKNOWN',
      type,
      whatsappResult
    )
  }

  // Overall success if at least one channel succeeded
  result.success =
    (result.channels.email?.success ?? false) ||
    (result.channels.whatsapp?.success ?? false)

  return result
}

/**
 * Send email notification
 */
async function sendEmailNotification(
  email: string,
  name: string | null,
  type: NotificationType,
  data: Record<string, string>
): Promise<{ success: boolean; error?: string }> {
  try {
    switch (type) {
      case 'MAGIC_LINK':
        await sendMagicLinkEmail(email, data.url)
        return { success: true }

      case 'JURY_INVITATION':
        await sendJuryInvitationEmail(
          email,
          name,
          data.inviteUrl,
          data.roundName
        )
        return { success: true }

      case 'EVALUATION_REMINDER': {
        const baseUrl = process.env.NEXTAUTH_URL || 'https://portal.monaco-opc.com'
        await sendEvaluationReminderEmail(
          email,
          name,
          parseInt(data.pendingCount || '0'),
          data.roundName || 'Current Round',
          data.deadline || 'Soon',
          data.assignmentsUrl || `${baseUrl}/jury/assignments`
        )
        return { success: true }
      }

      case 'ANNOUNCEMENT':
        await sendAnnouncementEmail(
          email,
          name,
          data.title || 'Announcement',
          data.message || '',
          data.ctaText,
          data.ctaUrl
        )
        return { success: true }

      default:
        return { success: false, error: `Unknown notification type: ${type}` }
    }
  } catch (error) {
    return {
      success: false,
      error: error instanceof Error ? error.message : 'Email send failed',
    }
  }
}

/**
 * Send WhatsApp notification
 */
async function sendWhatsAppNotification(
  phoneNumber: string,
  name: string | null,
  type: NotificationType,
  data: Record<string, string>
): Promise<{ success: boolean; messageId?: string; error?: string }> {
  const provider = await getWhatsAppProvider()

  if (!provider) {
    return { success: false, error: 'WhatsApp not configured' }
  }

  try {
    // Map notification types to templates
    const templateMap: Record<NotificationType, string> = {
      MAGIC_LINK: 'mopc_magic_link',
      JURY_INVITATION: 'mopc_jury_invitation',
      EVALUATION_REMINDER: 'mopc_evaluation_reminder',
      ANNOUNCEMENT: 'mopc_announcement',
    }

    const template = templateMap[type]

    // Build template params
    const params: Record<string, string> = {
      name: name || 'User',
      ...data,
    }

    const result = await provider.sendTemplate(phoneNumber, template, params)
    return result
  } catch (error) {
    return {
      success: false,
      error: error instanceof Error ? error.message : 'WhatsApp send failed',
    }
  }
}

/**
 * Log notification to database
 */
async function logNotification(
  userId: string,
  channel: NotificationChannel,
  provider: string,
  type: NotificationType,
  result: { success: boolean; messageId?: string; error?: string }
): Promise<void> {
  try {
    await prisma.notificationLog.create({
      data: {
        userId,
        channel,
        provider,
        type,
        status: result.success ? 'SENT' : 'FAILED',
        externalId: result.messageId,
        errorMsg: result.error,
      },
    })
  } catch (error) {
    console.error('Failed to log notification:', error)
  }
}

/**
 * Send bulk notifications to multiple users
 */
export async function sendBulkNotification(
  userIds: string[],
  type: NotificationType,
  data: Record<string, string>
): Promise<{ sent: number; failed: number }> {
  let sent = 0
  let failed = 0

  for (const userId of userIds) {
    const result = await sendNotification(userId, type, data)
    if (result.success) {
      sent++
    } else {
      failed++
    }
  }

  return { sent, failed }
}

/**
 * Get notification statistics
 */
export async function getNotificationStats(options?: {
  userId?: string
  startDate?: Date
  endDate?: Date
}): Promise<{
  total: number
  byChannel: Record<string, number>
  byStatus: Record<string, number>
  byType: Record<string, number>
}> {
  const where: Record<string, unknown> = {}

  if (options?.userId) {
    where.userId = options.userId
  }
  if (options?.startDate || options?.endDate) {
    where.createdAt = {}
    if (options.startDate) {
      (where.createdAt as Record<string, Date>).gte = options.startDate
    }
    if (options.endDate) {
      (where.createdAt as Record<string, Date>).lte = options.endDate
    }
  }

  const [total, byChannel, byStatus, byType] = await Promise.all([
    prisma.notificationLog.count({ where }),
    prisma.notificationLog.groupBy({
      by: ['channel'],
      where,
      _count: true,
    }),
    prisma.notificationLog.groupBy({
      by: ['status'],
      where,
      _count: true,
    }),
    prisma.notificationLog.groupBy({
      by: ['type'],
      where,
      _count: true,
    }),
  ])

  return {
    total,
    byChannel: Object.fromEntries(
      byChannel.map((r) => [r.channel, r._count])
    ),
    byStatus: Object.fromEntries(
      byStatus.map((r) => [r.status, r._count])
    ),
    byType: Object.fromEntries(
      byType.map((r) => [r.type, r._count])
    ),
  }
}
