Clear        


                
                    using CORE.APP.Models;
using CORE.APP.Services;
using MediatR;
using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations;
using Users.APP.Domain;

namespace Users.APP.Features.Users
{
    // request properties are created according to the data that will be retrieved from APIs or UIs
    public class UserUpdateRequest : Request, IRequest<CommandResponse> 
    {
        // copy all the non navigation properties from User entity
        [Required, StringLength(30, MinimumLength = 4)]
        public string UserName { get; set; }

        [Required, StringLength(15, MinimumLength = 3)]
        public string Password { get; set; }

        [StringLength(50)]
        public string FirstName { get; set; }

        [StringLength(50)]
        public string LastName { get; set; }

        public Genders Gender { get; set; }

        public DateTime? BirthDate { get; set; }

        //public DateTime RegistrationDate { get; set; } // we don't need this property in the request
                                                         // since we won't update it and get its value from the API or UI

        [Range(0, 5)] // minimum value can be 0, maximum value can be 5
        public decimal Score { get; set; }

        public bool IsActive { get; set; }

        public string Address { get; set; }

        // [Required] // can be defined if each user must have a country
        public int? CountryId { get; set; }

        //[Required] // can be defined if each user must have a city
        public int? CityId { get; set; }

        //[Reqired] // can be defined if each user must have a group
        public int? GroupId { get; set; }

        //[Required] // can be defined if each user must have at least one role
        public List<int> RoleIds { get; set; } = new List<int>();
    }

    public class UserUpdateHandler : Service<User>, IRequestHandler<UserUpdateRequest, CommandResponse>
    {
        public UserUpdateHandler(DbContext db) : base(db)
        {
        }

        // Since User entity has relational UserRole entities and the RoleIds of the User entity will be updated in the Handle method,
        // we first need to delete the relational UserRoles in the Handle method.
        // Therefore, we include the UserRoles to the query to get the relational UserRoles data to be deleted.
        protected override IQueryable<User> Query(bool isNoTracking = true)
        {
            return base.Query(isNoTracking).Include(u => u.UserRoles);
        }

        public async Task<CommandResponse> Handle(UserUpdateRequest request, CancellationToken cancellationToken)
        {
            // u: User entity delegate. Check if an active user excluding the current updated user with the same user name exists.
            if (await Query().AnyAsync(u => u.Id != request.Id && u.IsActive && u.UserName == request.UserName, cancellationToken))
                return Error("Active user with the same user name exists!");

            // get the User entity by ID from the Users table
            // isNoTracking is false for being tracked by EF Core to update the entity
            var entity = await Query(false).SingleOrDefaultAsync(u => u.Id == request.Id, cancellationToken);
            if (entity is null)
                return Error("User not found!");

            // delete the relational UserRole entities data
            Delete(entity.UserRoles); // will remove the relational entities data from the UserRoles DbSet as: _db.UserRoles.RemoveRange(entity.UserRoles)

            // update retrieved User entity's properties with request properties
            entity.UserName = request.UserName;
            entity.Password = request.Password;
            entity.FirstName = request.FirstName?.Trim(); // ? is used because request.FirstName can be null
            entity.LastName = request.LastName?.Trim(); // ? is used because request.LastName can be null
            entity.Gender = request.Gender;
            entity.BirthDate = request.BirthDate;
            entity.Score = request.Score;
            entity.IsActive = request.IsActive;
            entity.Address = request.Address?.Trim(); // ? is used because request.Address can be null
            entity.CountryId = request.CountryId;
            entity.CityId = request.CityId;
            entity.GroupId = request.GroupId;
            entity.RoleIds = request.RoleIds;

            await Update(entity, cancellationToken); // will update the entity in the Users DbSet and since save default parameter's value is true, will save changes to the database

            return Success("User updated successfully.", entity.Id);
        }
    }
}