using Brizco.Domain.Entities.Shift;

namespace Brizco.Repository.Handlers.Shift;

public class GetShiftPlansQueryHandler : IRequestHandler<GetShiftsQuery, List<ShiftSDto>>
{
    private readonly IRepositoryWrapper _repositoryWrapper;
    private readonly ICurrentUserService _currentUserService;

    public GetShiftPlansQueryHandler(IRepositoryWrapper repositoryWrapper, ICurrentUserService currentUserService)
    {
        _repositoryWrapper = repositoryWrapper;
        _currentUserService = currentUserService;
    }
    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 = new List<ShiftSDto>();
        if (request.SelectedDate > 0)
        {
            var selectedDate = DateTimeExtensions.UnixTimeStampToDateTime(request.SelectedDate);

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

            shifts = await originalShifts.AsNoTracking().Select(ShiftMapper.ProjectToSDto).ToListAsync(cancellationToken);
            foreach (var shift in shifts)
            {
                var activitiesCount = await _repositoryWrapper.SetRepository<Domain.Entities.Task.Activity>()
                    .TableNoTracking
                    .CountAsync(a => a.SetFor.Date == selectedDate.Date && a.ShiftId == shift.Id, cancellationToken);
                var doneActivitiesCount = await _repositoryWrapper.SetRepository<Domain.Entities.Task.Activity>()
                    .TableNoTracking
                    .CountAsync(a => a.Status == ActivityStatus.Done && a.SetFor.Date == selectedDate.Date && a.ShiftId == shift.Id, cancellationToken);
                var undoneActivitiesCount = await _repositoryWrapper.SetRepository<Domain.Entities.Task.Activity>()
                    .TableNoTracking
                    .CountAsync(a => a.Status == ActivityStatus.UnDone && a.SetFor.Date == selectedDate.Date && a.ShiftId == shift.Id, cancellationToken);
                shift.UndoneActivitiesCount = undoneActivitiesCount;
                shift.DoneActivitiesCount = doneActivitiesCount;
                shift.TotalActivitiesCount = activitiesCount;

                var existedShiftPlan = await _repositoryWrapper.SetRepository<Domain.Entities.Shift.ShiftPlan>()
                    .TableNoTracking
                    .FirstOrDefaultAsync(s => s.ShiftId == shift.Id && s.PlanFor.Date == selectedDate.Date, cancellationToken);
                shift.IsCompleted = existedShiftPlan?.IsCompleted ?? false;
                shift.CurrentShiftPlanId = existedShiftPlan?.Id ?? default;
                shift.HasCurrentShiftPlan = existedShiftPlan != null;
            }
        }
        else
        {

            shifts = await _repositoryWrapper.SetRepository<Domain.Entities.Shift.Shift>().TableNoTracking
                .Where(s => s.ComplexId == complexId)
                .OrderByDescending(s => s.CreatedAt)
                .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;
    }
}