import { NextRequest, NextResponse } from 'next/server'; import { getServerSession } from 'next-auth'; import { authOptions } from '@/lib/auth'; import { prisma } from '@/lib/prisma'; import { AttendanceStatus } from '@prisma/client'; export async function GET(request: NextRequest) { try { // Verificar sesión const session = await getServerSession(authOptions); if (!session?.user?.id) { return NextResponse.json( { error: 'No autorizado' }, { status: 401 } ); } // Verificar que el usuario sea estudiante const user = await prisma.user.findUnique({ where: { id: session.user.id }, include: { student: true } }); if (!user || user.role !== 'STUDENT' || !user.student) { return NextResponse.json( { error: 'Acceso denegado. Solo estudiantes pueden acceder.' }, { status: 403 } ); } // Obtener parámetros de consulta const { searchParams } = new URL(request.url); const sectionId = searchParams.get('sectionId'); const status = searchParams.get('status') as AttendanceStatus | 'all' | null; const startDate = searchParams.get('startDate'); const endDate = searchParams.get('endDate'); const periodId = searchParams.get('periodId'); // Construir filtros const whereClause: any = { studentId: user.student.id, }; if (sectionId && sectionId !== 'all') { whereClause.sectionId = sectionId; } if (status && status !== 'all') { whereClause.status = status; } if (startDate) { whereClause.date = { ...whereClause.date, gte: new Date(startDate) }; } if (endDate) { whereClause.date = { ...whereClause.date, lte: new Date(endDate) }; } // Si se especifica un período, filtrar por secciones de ese período if (periodId && periodId !== 'all') { whereClause.section = { class: { periodId: periodId } }; } // Obtener registros de asistencia const attendanceRecords = await prisma.attendance.findMany({ where: whereClause, include: { section: { include: { class: { include: { period: true } }, teacherAssignments: { where: { isActive: true }, include: { teacher: true } } } } }, orderBy: { date: 'desc' } }); // Obtener estadísticas generales const totalRecords = attendanceRecords.length; const presentCount = attendanceRecords.filter(r => r.status === 'PRESENT').length; const absentCount = attendanceRecords.filter(r => r.status === 'ABSENT').length; const justifiedCount = attendanceRecords.filter(r => r.status === 'JUSTIFIED').length; const attendanceRate = totalRecords > 0 ? Math.round((presentCount / totalRecords) * 100) : 0; // Estadísticas por sección const sectionStats = attendanceRecords.reduce((acc, record) => { const sectionId = record.sectionId; if (!acc[sectionId]) { acc[sectionId] = { sectionId, sectionName: record.section.name, className: record.section.class.name, classCode: record.section.class.code, periodName: record.section.class.period.name, total: 0, present: 0, absent: 0, justified: 0, attendanceRate: 0 }; } acc[sectionId].total++; if (record.status === 'PRESENT') acc[sectionId].present++; if (record.status === 'ABSENT') acc[sectionId].absent++; if (record.status === 'JUSTIFIED') acc[sectionId].justified++; acc[sectionId].attendanceRate = Math.round( (acc[sectionId].present / acc[sectionId].total) * 100 ); return acc; }, {} as Record); // Estadísticas por período const periodStats = attendanceRecords.reduce((acc, record) => { const periodId = record.section.class.period.id; if (!acc[periodId]) { acc[periodId] = { periodId, periodName: record.section.class.period.name, isActive: record.section.class.period.isActive, total: 0, present: 0, absent: 0, justified: 0, attendanceRate: 0 }; } acc[periodId].total++; if (record.status === 'PRESENT') acc[periodId].present++; if (record.status === 'ABSENT') acc[periodId].absent++; if (record.status === 'JUSTIFIED') acc[periodId].justified++; acc[periodId].attendanceRate = Math.round( (acc[periodId].present / acc[periodId].total) * 100 ); return acc; }, {} as Record); // Obtener todas las secciones matriculadas para filtros const enrolledSections = await prisma.studentEnrollment.findMany({ where: { studentId: user.student.id, isActive: true }, include: { section: { include: { class: { include: { period: true } } } } } }); // Obtener períodos únicos const periods = Array.from( new Set( enrolledSections.map(e => e.section.class.period) ) ).filter((period, index, self) => self.findIndex(p => p.id === period.id) === index ); return NextResponse.json({ student: { id: user.student.id, firstName: user.student.firstName, lastName: user.student.lastName, admissionNumber: user.student.admissionNumber }, attendanceRecords: attendanceRecords.map(record => ({ id: record.id, date: record.date, status: record.status, reason: record.reason, section: { id: record.section.id, name: record.section.name, class: { id: record.section.class.id, name: record.section.class.name, code: record.section.class.code, period: { id: record.section.class.period.id, name: record.section.class.period.name, isActive: record.section.class.period.isActive } }, teachers: record.section.teacherAssignments.map(ta => ({ id: ta.teacher.id, firstName: ta.teacher.firstName, lastName: ta.teacher.lastName, email: ta.teacher.email })) } })), statistics: { overall: { totalRecords, present: presentCount, absent: absentCount, justified: justifiedCount, attendanceRate }, bySections: Object.values(sectionStats), byPeriods: Object.values(periodStats) }, filters: { sections: enrolledSections.map(e => ({ id: e.section.id, name: e.section.name, className: e.section.class.name, classCode: e.section.class.code, periodName: e.section.class.period.name })), periods: periods.map(p => ({ id: p.id, name: p.name, isActive: p.isActive })) } }); } catch (error) { console.error('Error al obtener historial de asistencia:', error); return NextResponse.json( { error: 'Error interno del servidor' }, { status: 500 } ); } }