import { NextRequest, NextResponse } from 'next/server' import { getServerSession } from 'next-auth' import { authOptions } from '@/lib/auth' import { prisma } from '@/lib/db' export async function GET(request: NextRequest) { try { const session = await getServerSession(authOptions) if (!session?.user) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) } const now = new Date() const today = new Date(now.getFullYear(), now.getMonth(), now.getDate()) const weekAgo = new Date(today.getTime() - 7 * 24 * 60 * 60 * 1000) const monthAgo = new Date(today.getTime() - 30 * 24 * 60 * 60 * 1000) // Fetch all data in parallel const [ // Task counts by status tasksByStatus, // Task counts by priority tasksByPriority, // Task counts by department tasksByDepartment, // Overdue tasks overdueTasks, // Tasks due today dueTodayTasks, // Tasks due this week dueThisWeekTasks, // User workload (tasks per assignee) userWorkload, // Recently completed tasks (last 7 days) recentlyCompleted, // Tasks created in last 30 days tasksCreatedLast30Days, // Tasks completed in last 30 days tasksCompletedLast30Days, // Total tasks totalTasks, // Active users activeUsers, ] = await Promise.all([ // Tasks by status prisma.task.groupBy({ by: ['status'], _count: { id: true }, }), // Tasks by priority prisma.task.groupBy({ by: ['priority'], _count: { id: true }, }), // Tasks by department prisma.task.groupBy({ by: ['department'], _count: { id: true }, }), // Overdue tasks (past due, not completed) prisma.task.count({ where: { dueDate: { lt: today }, status: { notIn: ['COMPLETED', 'CANCELLED', 'NA'] }, }, }), // Due today prisma.task.count({ where: { dueDate: { gte: today, lt: new Date(today.getTime() + 24 * 60 * 60 * 1000), }, status: { notIn: ['COMPLETED', 'CANCELLED', 'NA'] }, }, }), // Due this week prisma.task.count({ where: { dueDate: { gte: today, lt: new Date(today.getTime() + 7 * 24 * 60 * 60 * 1000), }, status: { notIn: ['COMPLETED', 'CANCELLED', 'NA'] }, }, }), // User workload - tasks assigned per user prisma.user.findMany({ where: { isActive: true }, select: { id: true, displayName: true, email: true, department: true, taskAssignments: { include: { task: { select: { id: true, status: true, priority: true, dueDate: true, }, }, }, }, }, }), // Recently completed prisma.task.count({ where: { status: 'COMPLETED', completedAt: { gte: weekAgo }, }, }), // Tasks created last 30 days prisma.task.count({ where: { createdAt: { gte: monthAgo }, }, }), // Tasks completed last 30 days prisma.task.count({ where: { status: 'COMPLETED', completedAt: { gte: monthAgo }, }, }), // Total tasks prisma.task.count(), // Active users with task assignments prisma.user.count({ where: { isActive: true, taskAssignments: { some: {} }, }, }), ]) // Calculate user-level metrics const userMetrics = userWorkload.map((user) => { const tasks = user.taskAssignments.map((a) => a.task) const activeTasks = tasks.filter( (t) => !['COMPLETED', 'CANCELLED', 'NA'].includes(t.status) ) const completedTasks = tasks.filter((t) => t.status === 'COMPLETED') const overdue = activeTasks.filter( (t) => new Date(t.dueDate) < today ) const highPriority = activeTasks.filter( (t) => t.priority === 'HIGH' || t.priority === 'URGENT' ) return { id: user.id, name: user.displayName || user.email, department: user.department, totalAssigned: tasks.length, activeTasks: activeTasks.length, completedTasks: completedTasks.length, overdueTasks: overdue.length, highPriorityTasks: highPriority.length, completionRate: tasks.length > 0 ? Math.round((completedTasks.length / tasks.length) * 100) : 0, } }) // Sort users by active tasks (highest workload first) userMetrics.sort((a, b) => b.activeTasks - a.activeTasks) // Calculate summary metrics const totalActive = tasksByStatus .filter((s) => !['COMPLETED', 'CANCELLED', 'NA'].includes(s.status)) .reduce((sum, s) => sum + s._count.id, 0) const totalCompleted = tasksByStatus.find((s) => s.status === 'COMPLETED')?._count.id || 0 const completionRate = totalTasks > 0 ? Math.round((totalCompleted / totalTasks) * 100) : 0 // Calculate workload distribution const avgTasksPerUser = activeUsers > 0 ? Math.round(totalActive / activeUsers) : 0 const maxWorkload = Math.max(...userMetrics.map((u) => u.activeTasks), 0) const minWorkload = Math.min(...userMetrics.filter((u) => u.activeTasks > 0).map((u) => u.activeTasks), 0) // Format status breakdown const statusBreakdown = { notStarted: tasksByStatus.find((s) => s.status === 'NOT_STARTED')?._count.id || 0, inProgress: tasksByStatus.find((s) => s.status === 'IN_PROGRESS')?._count.id || 0, completed: totalCompleted, blocked: tasksByStatus.find((s) => s.status === 'BLOCKED')?._count.id || 0, na: tasksByStatus.find((s) => s.status === 'NA')?._count.id || 0, cancelled: tasksByStatus.find((s) => s.status === 'CANCELLED')?._count.id || 0, } // Format priority breakdown const priorityBreakdown = { low: tasksByPriority.find((p) => p.priority === 'LOW')?._count.id || 0, medium: tasksByPriority.find((p) => p.priority === 'MEDIUM')?._count.id || 0, high: tasksByPriority.find((p) => p.priority === 'HIGH')?._count.id || 0, urgent: tasksByPriority.find((p) => p.priority === 'URGENT')?._count.id || 0, } // Format department breakdown const departmentBreakdown = tasksByDepartment.reduce( (acc, d) => { acc[d.department] = d._count.id return acc }, {} as Record ) return NextResponse.json({ summary: { totalTasks, activeTasks: totalActive, completedTasks: totalCompleted, completionRate, overdueTasks, dueTodayTasks, dueThisWeekTasks, activeUsers, avgTasksPerUser, maxWorkload, minWorkload, }, trends: { recentlyCompleted, tasksCreatedLast30Days, tasksCompletedLast30Days, velocity: tasksCompletedLast30Days, // Tasks completed per 30 days }, breakdowns: { status: statusBreakdown, priority: priorityBreakdown, department: departmentBreakdown, }, userWorkload: userMetrics, }) } catch (error) { console.error('Workload KPI API error:', error) return NextResponse.json({ error: 'Internal server error' }, { status: 500 }) } }