namespace Brizco.Repository.Handlers.Shifts;

public class GetShiftPlansQueryHandler(IRepositoryWrapper repositoryWrapper, UserManager<ApplicationUser> userManager, ICurrentUserService currentUserService)
    : IRequestHandler<GetShiftsQuery, List<ShiftSDto>>
{
    public async Task<List<ShiftSDto>> Handle(GetShiftsQuery request, CancellationToken cancellationToken)
    {
        if (currentUserService.ComplexId == null)
            throw new AppException("ComplexId is null", ApiResultStatusCode.NotFound);
        if (!Guid.TryParse(currentUserService.ComplexId, out Guid complexId))
            throw new AppException("ComplexId is wrong", ApiResultStatusCode.NotFound);
        List<ShiftSDto> shifts;

        if (request.SelectedDate > 0)
        {
            var selectedDate = DateTimeExtensions.UnixTimeStampToDateTime(request.SelectedDate);

            var originalShifts = from shiftDay in repositoryWrapper.SetRepository<ShiftDay>().Entities
                                 join shift in repositoryWrapper.SetRepository<Shift>().Entities on shiftDay.ShiftId equals shift.Id
                                 where shiftDay.DayOfWeek == selectedDate.DayOfWeek && shift.ComplexId == complexId
                                 orderby shift.StartAt 
                                 select shift;

            shifts = await originalShifts.AsNoTracking().Select(ShiftMapper.ProjectToSDto).ToListAsync(cancellationToken);
            foreach (var shift in shifts)
            {
                var existedShiftPlan = await repositoryWrapper.SetRepository<ShiftPlan>()
                    .TableNoTracking
                    .FirstOrDefaultAsync(s => s.ShiftId == shift.Id && s.PlanFor.Date == selectedDate.Date, cancellationToken);
                if(existedShiftPlan == null)
                    continue;
                var supervisor = await userManager.FindByIdAsync(existedShiftPlan.SupervisorId.ToString());
                if (supervisor != null)
                    shift.CurrentSupervisorFullName = supervisor.FirstName + " " + supervisor.LastName;

                var activitiesCount = await repositoryWrapper.SetRepository<Domain.Entities.Tasks.Activity>()
                    .TableNoTracking
                    .CountAsync(a => a.SetFor.Date == selectedDate.Date && a.ShiftPlanId == existedShiftPlan.Id, cancellationToken);
                var doneActivitiesCount = await repositoryWrapper.SetRepository<Domain.Entities.Tasks.Activity>()
                    .TableNoTracking
                    .CountAsync(a => a.Status == ActivityStatus.Done && a.SetFor.Date == selectedDate.Date && a.ShiftPlanId == existedShiftPlan.Id, cancellationToken);
                var undoneActivitiesCount = await repositoryWrapper.SetRepository<Domain.Entities.Tasks.Activity>()
                    .TableNoTracking
                    .CountAsync(a => a.Status == ActivityStatus.UnDone && a.SetFor.Date == selectedDate.Date && a.ShiftPlanId == existedShiftPlan.Id, cancellationToken);
                shift.UndoneActivitiesCount = undoneActivitiesCount;
                shift.DoneActivitiesCount = doneActivitiesCount;
                shift.TotalActivitiesCount = activitiesCount;

                switch (currentUserService.RoleName)
                {
                    case null:
                        continue;
                    case ApplicationRoles.SuperVisor:
                    {
                        if (!Guid.TryParse(currentUserService.UserId, out Guid userId))
                            throw new AppException("User id is wrong");
                        var existedSupervisorShiftPlan = await repositoryWrapper.SetRepository<ShiftPlan>()
                            .TableNoTracking
                            .FirstOrDefaultAsync(s => s.ShiftId == shift.Id && s.PlanFor.Date == selectedDate.Date && s.SupervisorId == userId, cancellationToken);
                        shift.IsCompleted = existedSupervisorShiftPlan?.IsCompleted ?? false;
                        shift.CurrentShiftPlanId = existedSupervisorShiftPlan?.Id ?? default;
                        shift.HasCurrentShiftPlan = existedSupervisorShiftPlan != null;
                        break;
                    }
                    case ApplicationRoles.Manager:
                    {
                        shift.IsCompleted = existedShiftPlan?.IsCompleted ?? false;
                        shift.CurrentShiftPlanId = existedShiftPlan?.Id ?? default;
                        shift.HasCurrentShiftPlan = existedShiftPlan != null;
                        break;
                    }
                }
            }
        }
        else
        {

            shifts = await repositoryWrapper.SetRepository<Shift>().TableNoTracking
                .Where(s => s.ComplexId == complexId)
                .OrderBy(s => s.StartAt)
                .Skip(request.Page * 15).Take(15)
                .Select(ShiftMapper.ProjectToSDto)
                .ToListAsync(cancellationToken);

        }

        foreach (var shift in shifts)
        {
            var shiftDays = new List<DayOfWeek>();
            shift.Days.OrderBy(d => d).ToList().ForEach(d =>
            {
                if (d == DayOfWeek.Saturday)
                    shiftDays.Insert(0, d);
                else
                    shiftDays.Add(d);
            });
            shift.Days = shiftDays;
        }

        return shifts;
    }
}