/**
 * Notification Router
 *
 * Handles in-app notification CRUD operations for users.
 */

import { z } from 'zod'
import { router, protectedProcedure, adminProcedure } from '../trpc'
import {
  markNotificationAsRead,
  markAllNotificationsAsRead,
  getUnreadCount,
  deleteExpiredNotifications,
  deleteOldNotifications,
  NotificationIcons,
  NotificationPriorities,
} from '../services/in-app-notification'
import { sendStyledNotificationEmail, NOTIFICATION_EMAIL_TEMPLATES } from '@/lib/email'

export const notificationRouter = router({
  /**
   * List notifications for the current user
   */
  list: protectedProcedure
    .input(
      z.object({
        unreadOnly: z.boolean().default(false),
        limit: z.number().int().min(1).max(100).default(50),
        cursor: z.string().optional(), // For infinite scroll pagination
      })
    )
    .query(async ({ ctx, input }) => {
      const { unreadOnly, limit, cursor } = input
      const userId = ctx.user.id

      const where = {
        userId,
        ...(unreadOnly && { isRead: false }),
        // Don't show expired notifications
        OR: [{ expiresAt: null }, { expiresAt: { gt: new Date() } }],
      }

      const notifications = await ctx.prisma.inAppNotification.findMany({
        where,
        take: limit + 1, // Fetch one extra to check if there are more
        orderBy: { createdAt: 'desc' },
        ...(cursor && {
          cursor: { id: cursor },
          skip: 1, // Skip the cursor item
        }),
      })

      let nextCursor: string | undefined
      if (notifications.length > limit) {
        const nextItem = notifications.pop()
        nextCursor = nextItem?.id
      }

      return {
        notifications,
        nextCursor,
      }
    }),

  /**
   * Get unread notification count for the current user
   */
  getUnreadCount: protectedProcedure.query(async ({ ctx }) => {
    return getUnreadCount(ctx.user.id)
  }),

  /**
   * Check if there are any urgent unread notifications
   */
  hasUrgent: protectedProcedure.query(async ({ ctx }) => {
    const count = await ctx.prisma.inAppNotification.count({
      where: {
        userId: ctx.user.id,
        isRead: false,
        priority: 'urgent',
        OR: [{ expiresAt: null }, { expiresAt: { gt: new Date() } }],
      },
    })
    return count > 0
  }),

  /**
   * Mark a single notification as read
   */
  markAsRead: protectedProcedure
    .input(z.object({ id: z.string() }))
    .mutation(async ({ ctx, input }) => {
      await markNotificationAsRead(input.id, ctx.user.id)
      return { success: true }
    }),

  /**
   * Mark all notifications as read for the current user
   */
  markAllAsRead: protectedProcedure.mutation(async ({ ctx }) => {
    await markAllNotificationsAsRead(ctx.user.id)
    return { success: true }
  }),

  /**
   * Delete a notification (user can only delete their own)
   */
  delete: protectedProcedure
    .input(z.object({ id: z.string() }))
    .mutation(async ({ ctx, input }) => {
      await ctx.prisma.inAppNotification.deleteMany({
        where: {
          id: input.id,
          userId: ctx.user.id, // Ensure user can only delete their own
        },
      })
      return { success: true }
    }),

  /**
   * Get notification email settings (admin only)
   */
  getEmailSettings: adminProcedure.query(async ({ ctx }) => {
    return ctx.prisma.notificationEmailSetting.findMany({
      orderBy: [{ category: 'asc' }, { label: 'asc' }],
      include: {
        updatedBy: { select: { name: true, email: true } },
      },
    })
  }),

  /**
   * Update a notification email setting (admin only)
   */
  updateEmailSetting: adminProcedure
    .input(
      z.object({
        notificationType: z.string(),
        sendEmail: z.boolean(),
        emailSubject: z.string().optional(),
        emailTemplate: z.string().optional(),
      })
    )
    .mutation(async ({ ctx, input }) => {
      const { notificationType, sendEmail, emailSubject, emailTemplate } = input

      return ctx.prisma.notificationEmailSetting.upsert({
        where: { notificationType },
        update: {
          sendEmail,
          emailSubject,
          emailTemplate,
          updatedById: ctx.user.id,
        },
        create: {
          notificationType,
          category: 'custom',
          label: notificationType,
          sendEmail,
          emailSubject,
          emailTemplate,
          updatedById: ctx.user.id,
        },
      })
    }),

  /**
   * Delete expired notifications (admin cleanup)
   */
  deleteExpired: adminProcedure.mutation(async () => {
    const count = await deleteExpiredNotifications()
    return { deletedCount: count }
  }),

  /**
   * Delete old read notifications (admin cleanup)
   */
  deleteOld: adminProcedure
    .input(z.object({ olderThanDays: z.number().int().min(1).max(365).default(30) }))
    .mutation(async ({ input }) => {
      const count = await deleteOldNotifications(input.olderThanDays)
      return { deletedCount: count }
    }),

  /**
   * Get notification icon and priority mappings (for UI)
   */
  getMappings: protectedProcedure.query(() => {
    return {
      icons: NotificationIcons,
      priorities: NotificationPriorities,
    }
  }),

  /**
   * Admin: Get notification statistics
   */
  getStats: adminProcedure.query(async ({ ctx }) => {
    const [total, unread, byType, byPriority] = await Promise.all([
      ctx.prisma.inAppNotification.count(),
      ctx.prisma.inAppNotification.count({ where: { isRead: false } }),
      ctx.prisma.inAppNotification.groupBy({
        by: ['type'],
        _count: true,
        orderBy: { _count: { type: 'desc' } },
        take: 10,
      }),
      ctx.prisma.inAppNotification.groupBy({
        by: ['priority'],
        _count: true,
      }),
    ])

    return {
      total,
      unread,
      readRate: total > 0 ? ((total - unread) / total) * 100 : 0,
      byType: byType.map((t) => ({ type: t.type, count: t._count })),
      byPriority: byPriority.map((p) => ({ priority: p.priority, count: p._count })),
    }
  }),

  /**
   * Send a test notification email to the current admin
   */
  sendTestEmail: adminProcedure
    .input(z.object({ notificationType: z.string() }))
    .mutation(async ({ ctx, input }) => {
      const { notificationType } = input

      // Check if this notification type has a styled template
      const hasStyledTemplate = notificationType in NOTIFICATION_EMAIL_TEMPLATES

      // Get setting for label
      const setting = await ctx.prisma.notificationEmailSetting.findUnique({
        where: { notificationType },
      })

      // Sample data for test emails based on category
      const sampleData: Record<string, Record<string, unknown>> = {
        // Team notifications
        ADVANCED_SEMIFINAL: {
          projectName: 'Ocean Cleanup Initiative',
          programName: 'Monaco Ocean Protection Challenge 2026',
          nextSteps: 'Prepare your presentation for the semi-final round.',
        },
        ADVANCED_FINAL: {
          projectName: 'Ocean Cleanup Initiative',
          programName: 'Monaco Ocean Protection Challenge 2026',
          nextSteps: 'Get ready for the final presentation in Monaco.',
        },
        MENTOR_ASSIGNED: {
          projectName: 'Ocean Cleanup Initiative',
          mentorName: 'Dr. Marine Expert',
          mentorBio: 'Expert in marine conservation with 20 years of experience.',
        },
        NOT_SELECTED: {
          projectName: 'Ocean Cleanup Initiative',
          roundName: 'Semi-Final Round',
        },
        WINNER_ANNOUNCEMENT: {
          projectName: 'Ocean Cleanup Initiative',
          awardName: 'Grand Prize',
          prizeDetails: '€50,000 and mentorship program',
        },

        // Jury notifications
        ASSIGNED_TO_PROJECT: {
          projectName: 'Ocean Cleanup Initiative',
          roundName: 'Semi-Final Round',
          deadline: 'Friday, March 15, 2026',
        },
        BATCH_ASSIGNED: {
          projectCount: 5,
          roundName: 'Semi-Final Round',
          deadline: 'Friday, March 15, 2026',
        },
        ROUND_NOW_OPEN: {
          roundName: 'Semi-Final Round',
          projectCount: 12,
          deadline: 'Friday, March 15, 2026',
        },
        REMINDER_24H: {
          pendingCount: 3,
          roundName: 'Semi-Final Round',
          deadline: 'Tomorrow at 5:00 PM',
        },
        REMINDER_1H: {
          pendingCount: 2,
          roundName: 'Semi-Final Round',
          deadline: 'Today at 5:00 PM',
        },
        AWARD_VOTING_OPEN: {
          awardName: 'Innovation Award',
          finalistCount: 6,
          deadline: 'Friday, March 15, 2026',
        },

        // Mentor notifications
        MENTEE_ASSIGNED: {
          projectName: 'Ocean Cleanup Initiative',
          teamLeadName: 'John Smith',
          teamLeadEmail: 'john@example.com',
        },
        MENTEE_ADVANCED: {
          projectName: 'Ocean Cleanup Initiative',
          roundName: 'Semi-Final Round',
          nextRoundName: 'Final Round',
        },
        MENTEE_WON: {
          projectName: 'Ocean Cleanup Initiative',
          awardName: 'Innovation Award',
        },

        // Admin notifications
        NEW_APPLICATION: {
          projectName: 'New Ocean Project',
          applicantName: 'Jane Doe',
          applicantEmail: 'jane@example.com',
          programName: 'Monaco Ocean Protection Challenge 2026',
        },
        FILTERING_COMPLETE: {
          roundName: 'Initial Review',
          passedCount: 45,
          flaggedCount: 12,
          filteredCount: 8,
        },
        FILTERING_FAILED: {
          roundName: 'Initial Review',
          error: 'Connection timeout',
        },
      }

      const metadata = sampleData[notificationType] || {}
      const label = setting?.label || notificationType

      try {
        await sendStyledNotificationEmail(
          ctx.user.email,
          ctx.user.name || 'Admin',
          notificationType,
          {
            title: `[TEST] ${label}`,
            message: `This is a test email for the "${label}" notification type.`,
            linkUrl: `${process.env.NEXTAUTH_URL || 'https://portal.monaco-opc.com'}/admin/settings`,
            linkLabel: 'Back to Settings',
            metadata,
          }
        )

        return {
          success: true,
          message: `Test email sent to ${ctx.user.email}`,
          hasStyledTemplate,
        }
      } catch (error) {
        return {
          success: false,
          message: error instanceof Error ? error.message : 'Failed to send test email',
          hasStyledTemplate,
        }
      }
    }),
})
