using Brizco.Domain.Entities.Shift;

namespace Brizco.Repository.Handlers.ShiftPlan;

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

    public GetShiftPlansQueryHandler(IRepositoryWrapper repositoryWrapper, ICurrentUserService currentUserService)
    {
        _repositoryWrapper = repositoryWrapper;
        _currentUserService = currentUserService;
    }
    public async Task<List<ShiftPlanSDto>> Handle(GetShiftPlansQuery 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);

        IQueryable<Domain.Entities.Shift.ShiftPlan> baseQuery = _repositoryWrapper.SetRepository<Domain.Entities.Shift.ShiftPlan>()
            .TableNoTracking
            .OrderByDescending(s => s.CreatedAt)
            .Where(s => s.ComplexId == complexId);

        List<ShiftPlanSDto> shiftPlans = new List<ShiftPlanSDto>();

        if (request.SelectedDate == 0)
        {
            return await baseQuery
                .Skip(request.Page * 15).Take(15)
                .Select(ShiftPlanMapper.ProjectToSDto)
                .ToListAsync(cancellationToken);

        }
        else if (request.SelectedDate > 0)
        {
            if (request.SelectedDate > 0)
            {
                var selectedDate = DateTimeExtensions.UnixTimeStampToDateTime(request.SelectedDate);
                shiftPlans = await baseQuery.Where(s => s.PlanFor.Date == selectedDate.Date)
                    .Skip(request.Page * 15).Take(15)
                    .Select(ShiftPlanMapper.ProjectToSDto)
                    .ToListAsync(cancellationToken);
            }
            else
            {
                switch (request.DateTimeQueryFilter)
                {
                    case DateTimeQueryFilter.Today:
                        shiftPlans = await baseQuery.Where(s => s.PlanFor.Date == DateTime.Now.Date)
                            .Skip(request.Page * 15).Take(15)
                            .Select(ShiftPlanMapper.ProjectToSDto)
                            .ToListAsync(cancellationToken);
                        break;
                    case DateTimeQueryFilter.Yesterday:
                        shiftPlans = await baseQuery.Where(s => s.PlanFor.Date == DateTime.Now.AddDays(-1).Date)
                            .Skip(request.Page * 15).Take(15)
                            .Select(ShiftPlanMapper.ProjectToSDto)
                            .ToListAsync(cancellationToken);
                        break;
                    case DateTimeQueryFilter.PastWeek:
                        shiftPlans = await baseQuery.Where(s => s.PlanFor.Date >= DateTime.Now.AddDays(-7).Date)
                            .OrderByDescending(s => s.CreatedAt)
                            .Skip(request.Page * 15).Take(15)
                            .Select(ShiftPlanMapper.ProjectToSDto)
                            .ToListAsync(cancellationToken);
                        break;
                    case DateTimeQueryFilter.NextWeek:
                        shiftPlans = await baseQuery.Where(s => s.PlanFor.Date >= DateTime.Now.Date && s.PlanFor.Date <= DateTime.Today.AddDays(+7))
                            .OrderByDescending(s => s.CreatedAt)
                            .Skip(request.Page * 15).Take(15)
                            .Select(ShiftPlanMapper.ProjectToSDto)
                            .ToListAsync(cancellationToken);
                        break;
                    case DateTimeQueryFilter.PastMonth:
                        shiftPlans = await baseQuery.Where(s => s.PlanFor.Date >= DateTime.Now.AddDays(-31).Date)
                            .OrderByDescending(s => s.CreatedAt)
                            .Skip(request.Page * 15).Take(15)
                            .Select(ShiftPlanMapper.ProjectToSDto)
                            .ToListAsync(cancellationToken);
                        break;
                    case DateTimeQueryFilter.NextMonth:
                        shiftPlans = await baseQuery.Where(s => s.PlanFor.Date >= DateTime.Now.Date && s.PlanFor.Date <= DateTime.Today.AddDays(+31))
                            .OrderByDescending(s => s.CreatedAt)
                            .Skip(request.Page * 15).Take(15)
                            .Select(ShiftPlanMapper.ProjectToSDto)
                            .ToListAsync(cancellationToken);
                        break;
                    case null:
                        break;
                    default:
                        throw new ArgumentOutOfRangeException();
                }
            }

            foreach (var shiftPlan in shiftPlans)
            {
                var activitiesCount = await _repositoryWrapper.SetRepository<Domain.Entities.Task.Activity>()
                    .TableNoTracking
                    .CountAsync(a => a.SetFor.Date == shiftPlan.PlanFor.Date && a.ShiftId == shiftPlan.Id, cancellationToken);
                var doneActivitiesCount = await _repositoryWrapper.SetRepository<Domain.Entities.Task.Activity>()
                    .TableNoTracking
                    .CountAsync(a => a.Status == ActivityStatus.Done && a.SetFor.Date == shiftPlan.PlanFor.Date && a.ShiftId == shiftPlan.Id, cancellationToken);
                var undoneActivitiesCount = await _repositoryWrapper.SetRepository<Domain.Entities.Task.Activity>()
                    .TableNoTracking
                    .CountAsync(a => a.Status == ActivityStatus.UnDone && a.SetFor.Date == shiftPlan.PlanFor.Date && a.ShiftId == shiftPlan.Id, cancellationToken);
                shiftPlan.UndoneActivitiesCount = undoneActivitiesCount;
                shiftPlan.DoneActivitiesCount = doneActivitiesCount;
                shiftPlan.TotalActivitiesCount = activitiesCount;
            }
        }

        foreach (var shiftPlan in shiftPlans)
        {
            shiftPlan.StaffCount = await _repositoryWrapper.SetRepository<ShiftPlanUser>()
                .TableNoTracking
                .CountAsync(spu => spu.ShiftPlanId == shiftPlan.Id, cancellationToken);

        }

        return shiftPlans;
    }
}