using Brizco.Domain.Entities.Task;

namespace Brizco.Repository.Handlers.Task;

public class UpdateActivityCommandHandler : IRequestHandler<UpdateTaskCommand, bool>
{
    private readonly IRepositoryWrapper _repositoryWrapper;
    private readonly ICurrentUserService _currentUserService;

    public UpdateActivityCommandHandler(IRepositoryWrapper repositoryWrapper,ICurrentUserService currentUserService)
    {
        _repositoryWrapper = repositoryWrapper;
        _currentUserService = currentUserService;
    }

    public async Task<bool> Handle(UpdateTaskCommand request, CancellationToken cancellationToken)
    {
        var task = await _repositoryWrapper.SetRepository<Domain.Entities.Task.Task>()
            .TableNoTracking.FirstOrDefaultAsync(s => s.Id == request.Id,cancellationToken);
        if (task == null)
            throw new AppException("Task not found", ApiResultStatusCode.NotFound);

        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 newTask = Domain.Entities.Task.Task.Create(request.Title,
            request.Description,
            request.Type,
            request.IsDisposable,
            DateTimeExtensions.UnixTimeStampToDateTime(request.SetFor),
            request.HasDisposed,
            request.Amount,
            request.AmountType,
            complexId,
            request.ScheduleType);

        newTask.Id = request.Id;


        if (request.Routines.Count == 0)
            throw new AppException("لطفا روتین های وظیفه را انتخاب نمایید");
        var routines = await _repositoryWrapper.SetRepository<TaskRoutine>()
            .TableNoTracking
            .Where(tr => tr.TaskId == newTask.Id)
            .ToListAsync(cancellationToken);
        foreach (var taskRoutine in routines.Where(taskR => !request.Routines.Exists(r=>r== taskR.RoutineId)))
        {
            _repositoryWrapper.SetRepository<TaskRoutine>()
                .Delete(taskRoutine);
            await _repositoryWrapper.SaveChangesAsync(cancellationToken);
        }

        foreach (var routine in request.Routines.Where(requestRoutine => !routines.Exists(r=>r.RoutineId==requestRoutine)))
        {
            newTask.AddRoutine(routine);
        }

        if (request.Shifts.Count == 0)
            throw new AppException("اگر فعالیت برای یک گروه نقش انتخاب شده باشد باید لیست نقش ها را ارسال نمایید");
        var shifts = await _repositoryWrapper.SetRepository<TaskShift>()
            .TableNoTracking
            .Where(tr => tr.TaskId == newTask.Id)
            .ToListAsync(cancellationToken);
        foreach (var taskShift in shifts.Where(taskS => !request.Shifts.Exists(r => r == taskS.ShiftId)))
        {
            _repositoryWrapper.SetRepository<TaskShift>()
                .Delete(taskShift);
            await _repositoryWrapper.SaveChangesAsync(cancellationToken);
        }

        foreach (var shift in request.Shifts.Where(requestShift => !shifts.Exists(r => r.ShiftId == requestShift)))
        {
            newTask.AddShift(shift);
        }

        if (request.Positions.Count == 0)
            throw new AppException("اگر فعالیت برای یک گروه نقش انتخاب شده باشد باید لیست نقش ها را ارسال نمایید");
        var positions = await _repositoryWrapper.SetRepository<TaskPosition>()
            .TableNoTracking
            .Where(tr => tr.TaskId == newTask.Id)
            .ToListAsync(cancellationToken);
        foreach (var taskPosition in positions.Where(taskP => !request.Positions.Exists(r => r == taskP.PositionId)))
        {
            _repositoryWrapper.SetRepository<TaskPosition>()
                .Delete(taskPosition);
            await _repositoryWrapper.SaveChangesAsync(cancellationToken);
        }

        foreach (var position in request.Positions.Where(requestP => !positions.Exists(r => r.PositionId == requestP)))
        {
            newTask.AddPosition(position);
        }

        if (task.ScheduleType == TaskScheduleType.Weekly && request.Days.Count == 0)
            throw new AppException("اگر تکرار فعالیت به صورت هفتگی باشد باید روزهای ان هفته را انتخاب کنید");
        request.Days.ForEach(d => task.SetDay(d));
        var days = await _repositoryWrapper.SetRepository<TaskDay>()
            .TableNoTracking
            .Where(tr => tr.TaskId == newTask.Id)
            .ToListAsync(cancellationToken);
        foreach (var taskDay in days.Where(taskD => !request.Days.Exists(r => r == taskD.DayOfWeek)))
        {
            _repositoryWrapper.SetRepository<TaskDay>()
                .Delete(taskDay);
            await _repositoryWrapper.SaveChangesAsync(cancellationToken);
        }

        foreach (var day in request.Days.Where(requestP => !days.Exists(r => r.DayOfWeek == requestP)))
        {
            newTask.SetDay(day);
        }

        _repositoryWrapper.SetRepository<Domain.Entities.Task.Task>()
            .Update(newTask);
        await _repositoryWrapper.SaveChangesAsync(cancellationToken);

        return true;
    }
}