namespace Application.Enrollments.Queries;

using Application.Enrollments.DTOs;
using Domain.Exceptions;
using Domain.Ports.Repositories;
using MediatR;

public record GetClassmatesQuery(int StudentId) : IRequest<IReadOnlyList<ClassmatesBySubjectDto>>;

public class GetClassmatesHandler(
    IStudentRepository studentRepository,
    IEnrollmentRepository enrollmentRepository)
    : IRequestHandler<GetClassmatesQuery, IReadOnlyList<ClassmatesBySubjectDto>>
{
    public async Task<IReadOnlyList<ClassmatesBySubjectDto>> Handle(
        GetClassmatesQuery request,
        CancellationToken ct)
    {
        var student = await studentRepository.GetByIdWithEnrollmentsAsync(request.StudentId, ct)
            ?? throw new StudentNotFoundException(request.StudentId);

        if (student.Enrollments.Count == 0)
            return [];

        // Single batch query instead of N queries (eliminates N+1)
        var subjectIds = student.Enrollments.Select(e => e.SubjectId);
        var classmatesBySubject = await enrollmentRepository
            .GetClassmatesBatchAsync(request.StudentId, subjectIds, ct);

        return student.Enrollments.Select(enrollment => new ClassmatesBySubjectDto(
            enrollment.SubjectId,
            enrollment.Subject?.Name ?? "",
            classmatesBySubject.TryGetValue(enrollment.SubjectId, out var classmates)
                ? classmates.Select(c => new ClassmateDto(c.Id, c.Name)).ToList()
                : []
        )).ToList();
    }
}
