using MD.PersianDateTime.Standard;
using Activity = Brizco.Domain.Entities.Tasks.Activity;

namespace Brizco.Repository.Handlers.Users;

public class GetStaffQueryHandler(IRepositoryWrapper repositoryWrapper,ICurrentUserService currentUserService) : IRequestHandler<GetStaffQuery,List<StaffResponseSDto>>
{
    public async Task<List<StaffResponseSDto>> Handle(GetStaffQuery request, CancellationToken cancellationToken)
    {
        var count = request.Count ?? 10;
        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);

        var baseQuery = repositoryWrapper.SetRepository<Activity>()
            .TableNoTracking
            .OrderByDescending(s => s.CreatedAt)
            .Where(s => s.ComplexId == complexId);

        List<ActivitySDto> activities = new List<ActivitySDto>();

        switch (request.DateTimeQuery)
        {
            case DateTimeQueryFilter.Today:
                activities = await baseQuery.Where(s => s.SetFor.Date == DateTime.Now.Date)
                    .Skip(request.Page * count).Take(count)
                    .Select(ActivityMapper.ProjectToSDto)
                    .ToListAsync(cancellationToken);
                break;
            case DateTimeQueryFilter.Yesterday:
                activities = await baseQuery.Where(s => s.SetFor.Date == DateTime.Now.AddDays(-1).Date)
                    .Skip(request.Page * count).Take(count)
                    .Select(ActivityMapper.ProjectToSDto)
                    .ToListAsync(cancellationToken);
                break;
            case DateTimeQueryFilter.PastWeek:
                DateTime pastWeekToday = DateTime.Today;
                int pastWeekDelta = DayOfWeek.Saturday - pastWeekToday.DayOfWeek;
                if (pastWeekDelta > 0) pastWeekDelta -= 7;
                DateTime startOfPastWeek = DateTime.Today.AddDays(pastWeekDelta).AddDays(-7);
                DateTime endOfPastWeek = startOfPastWeek.AddDays(6);
                activities = await baseQuery.Where(s => s.SetFor.Date >= startOfPastWeek.Date && s.SetFor.Date <= endOfPastWeek.Date)
                    .OrderByDescending(s => s.CreatedAt)
                    .Select(ActivityMapper.ProjectToSDto)
                    .ToListAsync(cancellationToken);
                break;
            case DateTimeQueryFilter.NextWeek:
                DateTime startOfNextWeek = DateTime.Today.AddDays(7 - (int)DateTime.Today.DayOfWeek + 1);
                DateTime endOfNextWeek = startOfNextWeek.AddDays(6);
                activities = await baseQuery.Where(s => s.SetFor.Date >= startOfNextWeek.Date && s.SetFor.Date <= endOfNextWeek.Date)
                    .OrderByDescending(s => s.CreatedAt)
                    .Select(ActivityMapper.ProjectToSDto)
                    .ToListAsync(cancellationToken);
                break;
            case DateTimeQueryFilter.ThisWeek:
                DateTime today = DateTime.Today;
                int delta = DayOfWeek.Saturday - today.DayOfWeek;
                if (delta > 0) delta -= 7;
                DateTime startOfWeek = today.AddDays(delta);
                DateTime endOfWeek = startOfWeek.AddDays(6);
                activities = await baseQuery.Where(s => s.SetFor.Date >= startOfWeek.Date && s.SetFor.Date <= endOfWeek.Date)
                    .OrderByDescending(s => s.CreatedAt)
                    .Select(ActivityMapper.ProjectToSDto)
                    .ToListAsync(cancellationToken);
                break;
            case DateTimeQueryFilter.PastMonth:

                DateTime startOfPastMonth = new PersianDateTime(PersianDateTime.Today.AddMonths(-1).Year, PersianDateTime.Today.AddMonths(-1).Month, 1).ToDateTime();
                DateTime endOfPastMonth = startOfPastMonth.AddMonths(1);
                activities = await baseQuery.Where(s => s.SetFor.Date >= startOfPastMonth.Date && s.SetFor.Date < endOfPastMonth.Date)
                    .OrderByDescending(s => s.CreatedAt)
                    .Select(ActivityMapper.ProjectToSDto)
                    .ToListAsync(cancellationToken);
                break;
            case DateTimeQueryFilter.NextMonth:
                DateTime startOfNextMonth = new PersianDateTime(PersianDateTime.Today.AddMonths(1).Year, PersianDateTime.Today.AddMonths(1).Month, 1).ToDateTime();
                DateTime endOfNextMonth = startOfNextMonth.AddMonths(1);
                activities = await baseQuery.Where(s => s.SetFor.Date >= startOfNextMonth.Date && s.SetFor.Date < endOfNextMonth.Date)
                    .OrderByDescending(s => s.CreatedAt)
                    .Select(ActivityMapper.ProjectToSDto)
                    .ToListAsync(cancellationToken);
                break;

            case DateTimeQueryFilter.ThisMonth:
                DateTime startOfThisMonth = new PersianDateTime(PersianDateTime.Today.Year, PersianDateTime.Today.Month, 1).ToDateTime();
                DateTime endOfThisMonth = startOfThisMonth.AddMonths(1);
                activities = await baseQuery.Where(s => s.SetFor.Date >= startOfThisMonth.Date && s.SetFor.Date < endOfThisMonth.Date)
                    .OrderByDescending(s => s.CreatedAt)
                    .Select(ActivityMapper.ProjectToSDto)
                    .ToListAsync(cancellationToken);
                break;
            default:
                throw new ArgumentOutOfRangeException();

        }
        
        var staffs = activities.Select(a => new StaffResponseSDto
        {
            FirstName = a.UserFirstName,
            LastName = a.UserLastName,
            Id = a.UserId
        }).ToList();
        return staffs.DistinctBy(d => d.Id).ToList();
    }
}