import { z } from 'zod'
import { TRPCError } from '@trpc/server'
import { router, adminProcedure } from '../../trpc'
import { createBulkNotifications, NotificationTypes } from '../../services/in-app-notification'
import { logAudit } from '@/server/utils/audit'

export const assignmentNotificationsRouter = router({
  /**
   * Notify all jurors of their current assignments for a round (admin only).
   * Sends in-app notifications (emails are handled by maybeSendEmail via createBulkNotifications).
   */
  notifyJurorsOfAssignments: adminProcedure
    .input(z.object({ roundId: z.string() }))
    .mutation(async ({ ctx, input }) => {
      const round = await ctx.prisma.round.findUniqueOrThrow({
        where: { id: input.roundId },
        select: { name: true, windowCloseAt: true },
      })

      // Get all assignments grouped by user
      const assignments = await ctx.prisma.assignment.findMany({
        where: { roundId: input.roundId },
        select: { userId: true },
      })

      if (assignments.length === 0) {
        return { sent: 0, jurorCount: 0 }
      }

      // Count assignments per user
      const userCounts: Record<string, number> = {}
      for (const a of assignments) {
        userCounts[a.userId] = (userCounts[a.userId] || 0) + 1
      }

      const deadline = round.windowCloseAt
        ? new Date(round.windowCloseAt).toLocaleDateString('en-US', {
            weekday: 'long',
            year: 'numeric',
            month: 'long',
            day: 'numeric',
          })
        : undefined

      // Create in-app notifications grouped by project count
      const usersByProjectCount = new Map<number, string[]>()
      for (const [userId, projectCount] of Object.entries(userCounts)) {
        const existing = usersByProjectCount.get(projectCount) || []
        existing.push(userId)
        usersByProjectCount.set(projectCount, existing)
      }

      let totalSent = 0
      for (const [projectCount, userIds] of usersByProjectCount) {
        if (userIds.length === 0) continue
        await createBulkNotifications({
          userIds,
          type: NotificationTypes.BATCH_ASSIGNED,
          title: `${projectCount} Projects Assigned`,
          message: `You have been assigned ${projectCount} project${projectCount > 1 ? 's' : ''} to evaluate for ${round.name || 'this round'}.`,
          linkUrl: `/jury/competitions`,
          linkLabel: 'View Assignments',
          metadata: { projectCount, roundName: round.name, deadline },
        })
        totalSent += userIds.length
      }

      await logAudit({
        prisma: ctx.prisma,
        userId: ctx.user.id,
        action: 'NOTIFY_JURORS_OF_ASSIGNMENTS',
        entityType: 'Round',
        entityId: input.roundId,
        detailsJson: {
          jurorCount: Object.keys(userCounts).length,
          totalAssignments: assignments.length,
        },
        ipAddress: ctx.ip,
        userAgent: ctx.userAgent,
      })

      return { sent: totalSent, jurorCount: Object.keys(userCounts).length }
    }),

  notifySingleJurorOfAssignments: adminProcedure
    .input(z.object({ roundId: z.string(), userId: z.string() }))
    .mutation(async ({ ctx, input }) => {
      const round = await ctx.prisma.round.findUniqueOrThrow({
        where: { id: input.roundId },
        select: { name: true, windowCloseAt: true },
      })

      const assignments = await ctx.prisma.assignment.findMany({
        where: { roundId: input.roundId, userId: input.userId },
        select: { id: true },
      })

      if (assignments.length === 0) {
        throw new TRPCError({ code: 'NOT_FOUND', message: 'No assignments found for this juror in this round' })
      }

      const projectCount = assignments.length
      const deadline = round.windowCloseAt
        ? new Date(round.windowCloseAt).toLocaleDateString('en-US', {
            weekday: 'long',
            year: 'numeric',
            month: 'long',
            day: 'numeric',
          })
        : undefined

      await createBulkNotifications({
        userIds: [input.userId],
        type: NotificationTypes.BATCH_ASSIGNED,
        title: `${projectCount} Projects Assigned`,
        message: `You have been assigned ${projectCount} project${projectCount > 1 ? 's' : ''} to evaluate for ${round.name || 'this round'}.`,
        linkUrl: `/jury/competitions`,
        linkLabel: 'View Assignments',
        metadata: { projectCount, roundName: round.name, deadline },
      })

      await logAudit({
        prisma: ctx.prisma,
        userId: ctx.user.id,
        action: 'NOTIFY_SINGLE_JUROR_OF_ASSIGNMENTS',
        entityType: 'Round',
        entityId: input.roundId,
        detailsJson: {
          targetUserId: input.userId,
          assignmentCount: projectCount,
        },
        ipAddress: ctx.ip,
        userAgent: ctx.userAgent,
      })

      return { sent: 1, projectCount }
    }),
})
