import type { PrismaClient } from '@prisma/client'
import { createBulkNotifications, NotificationTypes } from '../../services/in-app-notification'

/** Evaluation statuses that are safe to move (not yet finalized). */
export const MOVABLE_EVAL_STATUSES = ['NOT_STARTED', 'DRAFT'] as const

/**
 * Groups a per-user assignment count map into batches by count, then sends
 * BATCH_ASSIGNED notifications via createBulkNotifications.
 *
 * @param userAssignmentCounts  - map of userId → number of newly-assigned projects
 * @param stageName             - display name of the round (for the notification message)
 * @param deadline              - formatted deadline string (optional)
 */
export async function buildBatchNotifications(
  userAssignmentCounts: Record<string, number>,
  stageName: string | null | undefined,
  deadline: string | undefined,
): Promise<void> {
  const usersByProjectCount = new Map<number, string[]>()
  for (const [userId, projectCount] of Object.entries(userAssignmentCounts)) {
    const existing = usersByProjectCount.get(projectCount) || []
    existing.push(userId)
    usersByProjectCount.set(projectCount, existing)
  }

  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 ${stageName || 'this stage'}.`,
      linkUrl: `/jury/competitions`,
      linkLabel: 'View Assignments',
      metadata: {
        projectCount,
        roundName: stageName,
        deadline,
      },
    })
  }
}

export type CandidateJuror = {
  id: string
  name: string | null
  email: string
  maxAssignments: number | null
}

/**
 * Builds the candidate juror pool for a round, scoped to the jury group if one
 * is assigned, otherwise falling back to all active JURY_MEMBER users who have
 * at least one assignment in the round.
 *
 * @param prisma        - Prisma client (or transaction client)
 * @param roundId       - round being processed
 * @param juryGroupId   - optional jury group id from the round
 * @param excludeUserId - userId to exclude from results (the source / dropped juror)
 */
export async function getCandidateJurors(
  prisma: PrismaClient,
  roundId: string,
  juryGroupId: string | null | undefined,
  excludeUserId: string,
): Promise<CandidateJuror[]> {
  if (juryGroupId) {
    const members = await prisma.juryGroupMember.findMany({
      where: { juryGroupId },
      include: {
        user: { select: { id: true, name: true, email: true, maxAssignments: true, status: true } },
      },
    })
    return members
      .filter((m) => m.user.status === 'ACTIVE' && m.user.id !== excludeUserId)
      .map((m) => m.user)
  }

  const roundJurorIds = await prisma.assignment.findMany({
    where: { roundId },
    select: { userId: true },
    distinct: ['userId'],
  })
  const ids = roundJurorIds.map((a) => a.userId).filter((id) => id !== excludeUserId)

  if (ids.length === 0) return []

  return prisma.user.findMany({
    where: { id: { in: ids }, roles: { has: 'JURY_MEMBER' }, status: 'ACTIVE' },
    select: { id: true, name: true, email: true, maxAssignments: true },
  })
}
