using MediatR;
using Microsoft.EntityFrameworkCore;
using Mirea.Api.DataAccess.Application.Interfaces.DbContexts.Schedule;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace Mirea.Api.DataAccess.Application.Cqrs.Schedule.Queries.GetScheduleList;

public class GetScheduleListQueryHandler(ILessonDbContext dbContext) : IRequestHandler<GetScheduleListQuery, ScheduleListVm>
{
    public async Task<ScheduleListVm> Handle(GetScheduleListQuery request, CancellationToken cancellationToken)
    {
        var query = dbContext.Lessons.AsQueryable();

        if (request.IsEven != null)
            query = query.Where(l => l.IsEven == request.IsEven);

        if (request.GroupIds != null && request.GroupIds.Length != 0)
            query = query.Where(l => request.GroupIds.Contains(l.GroupId));

        if (request.DisciplineIds != null && request.DisciplineIds.Length != 0)
            query = query.Where(l => request.DisciplineIds.Contains(l.DisciplineId));

        if (request.LectureHallIds != null && request.LectureHallIds.Length != 0)
            query = query.Where(l => l.LessonAssociations!.Any(la =>
                la.LectureHallId != null && request.LectureHallIds.Contains(la.LectureHallId.Value)));

        if (request.ProfessorIds != null && request.ProfessorIds.Length != 0)
            query = query.Where(l =>
                l.LessonAssociations!.Any(la =>
                    la.ProfessorId != null && request.ProfessorIds.Contains(la.ProfessorId.Value)));

        var data = await query
            .Include(lesson => lesson.Discipline!)
            .Include(lesson => lesson.SpecificWeeks)
            .Include(lesson => lesson.Group!)
            .Include(lesson => lesson.LessonAssociations!)
            .ThenInclude(lessonAssociation => lessonAssociation.TypeOfOccupation!)
            .Include(lesson => lesson.LessonAssociations!)
                .ThenInclude(lessonAssociation => lessonAssociation.Professor)
            .Include(lesson => lesson.LessonAssociations!)
                .ThenInclude(lessonAssociation => lessonAssociation.LectureHall)
                    .ThenInclude(lectureHall => lectureHall!.Campus).ToListAsync(cancellationToken);

        var result = data.Select(l => new ScheduleLookupDto()
        {
            DayOfWeek = l.DayOfWeek,
            PairNumber = l.PairNumber,
            IsEven = l.IsEven,
            TypeOfOccupations = l.LessonAssociations!
                .Where(la => !string.IsNullOrEmpty(la.TypeOfOccupation?.ShortName))
                .Select(la => la.TypeOfOccupation!.ShortName),

            Discipline = l.Discipline!.Name,
            DisciplineId = l.DisciplineId,

            IsExcludedWeeks = l.IsExcludedWeeks,
            Weeks = l.SpecificWeeks?.Select(w => w.WeekNumber),

            Group = l.Group!.Name,
            GroupId = l.GroupId,

            LectureHalls = l.LessonAssociations!
                .Where(la => !string.IsNullOrEmpty(la.LectureHall?.Name))
                .Select(la => la.LectureHall?.Name),
            LectureHallsId = l.LessonAssociations!
                .Where(la => la.LectureHallId != null)
                .Select(la => la.LectureHallId),

            Campus = l.LessonAssociations!
                .Where(la => !string.IsNullOrEmpty(la.LectureHall?.Campus?.CodeName))
                .Select(la => la.LectureHall?.Campus?.CodeName),
            CampusId = l.LessonAssociations!
                .Where(la => la.LectureHall?.Campus != null)
                .Select(la => la.LectureHall?.CampusId),

            Professors = l.LessonAssociations!
                .Where(la => !string.IsNullOrEmpty(la.Professor?.Name))
                .Select(la => la.Professor?.Name),
            ProfessorsId = l.LessonAssociations!
                .Where(la => la.ProfessorId != null)
                .Select(la => la.ProfessorId),

            LinkToMeet = l.LessonAssociations!.Select(la => la.LinkToMeet)
        }).ToList();

        return new ScheduleListVm
        {
            Schedules = result
        };
    }
}