Clear        


                
                    using CORE.APP.Models;
using CORE.APP.Services;
using MediatR;
using Microsoft.EntityFrameworkCore;
using Users.APP.Domain;
using Users.APP.Features.Users;

namespace Users.APP.Features.Roles
{
    public class RoleQueryRequest : Request, IRequest<IQueryable<RoleQueryResponse>>
    {
    }

    // response properties are created according to the data to be presented in API responses or UIs
    public class RoleQueryResponse : Response
    {
        // copy all the non navigation properties from Role entity
        public string Name { get; set; }



        // add the new properties, some ending with F for the properties with the same name, for custom or formatted string values
        // Way 1: Use user related properties for partial data
        public int UserCount { get; set; }
        public string UsersF { get; set; }
        // Way 2: Use user related UserQueryResponse collection property for full data
        // Either way 1, way 2 or both of them can be used
        public List<UserQueryResponse> Users { get; set; }
    }



    // Inherit from the generic entity service class therefore DbContext injected constructor can be automatically created
    // and entity CRUD (create, read, update, delete) methods in the base class can be invoked.
    public class RoleQueryHandler : Service<Role>, IRequestHandler<RoleQueryRequest, IQueryable<RoleQueryResponse>>
    {
        public RoleQueryHandler(DbContext db) : base(db)
        {
        }

        // base virtual DbSet method is overriden therefore the overriden entity query can be used in all other methods
        protected override IQueryable<Role> DbSet()
        {
            // r: Role entity delegate, ur: UserRole entity delegate
            return base.DbSet() // will return Roles DbSet
                .Include(r => r.UserRoles).ThenInclude(ur => ur.User) // will first include the relational UserRoles then User data
                .OrderBy(r => r.Name); // query will be ordered ascending by Name values

            // Include, ThenInclude, OrderBy, OrderByDescending, ThenBy and ThenByDescending methods can also be used with DbSets.
        }

        public Task<IQueryable<RoleQueryResponse>> Handle(RoleQueryRequest request, CancellationToken cancellationToken)
        {
            var query = DbSet().Select(r => new RoleQueryResponse()
            {
                // assigning entity properties to the response
                Id = r.Id,
                Name = r.Name,

                // assigning custom or formatted properties to the response
                // Way 1: Assign user related properties for partial data
                UserCount = r.UserRoles.Count, // returns the users count of each role
                UsersF = string.Join(", ", r.UserRoles.Select(ur => ur.User.UserName)), // returns a comma seperated user names string for each role
                // Way 2: Assign user related UserQueryResponse collection property for full data
                // Either way 1, way 2 or both of them can be applied
                Users = r.UserRoles.Select(ur => new UserQueryResponse
                {
                    // assign User entity properties to the response through each UserRole entity's User entity property
                    Id = ur.User.Id,
                    UserName = ur.User.UserName,
                    Password = ur.User.Password,
                    IsActive = ur.User.IsActive,
                    RegistrationDate = ur.User.RegistrationDate,
                    BirthDate = ur.User.BirthDate,
                    Score = ur.User.Score,
                    FirstName = ur.User.FirstName,
                    LastName = ur.User.LastName,
                    Gender = ur.User.Gender,
                    Address = ur.User.Address,
                    GroupId = ur.User.GroupId,
                    RoleIds = ur.User.RoleIds,
                    CountryId = ur.User.CountryId,
                    CityId = ur.User.CityId,

                    // assigning custom or formatted User entity properties through each UserRole entity's
                    // User entity property to the response

                    // concatenated first name and last name with a white space character
                    FullName = ur.User.FirstName + " " + ur.User.LastName,

                    // assign "Active" or "Inactive" for IsActive boolean property using ternary operator
                    IsActiveF = ur.User.IsActive ? "Active" : "Inactive", 
                    
                    // If User entity's BirthDate value is not null, convert and assign the value with month/day/year format, otherwise assign "".
                    // No need to give the second CultureInfo parameter (e.g. new CultureInfo("tr-TR")) to the ToString method since
                    // CultureInfo property was assigned in the constructor of the base or this class.
                    // Instead of ToString method, ToShortDateString (e.g. 08/18/2025) or ToLongDateString (e.g. Monday, August 18, 2025) methods can be used.
                    // For time ToShortTimeString (17:26) or ToLongTimeString (17:26:52) can be used.
                    // Again CultureInfo parameter is not needed for these methods.
                    BirthDateF = ur.User.BirthDate.HasValue ? ur.User.BirthDate.Value.ToString("MM/dd/yyyy") : string.Empty,

                    RegistrationDateF = ur.User.RegistrationDate.ToShortDateString(),
                    ScoreF = ur.User.Score.ToString("N1"), // N: number format, C: currency format, 1: one decimal
                    GenderF = ur.User.Gender.ToString() // will assign Woman or Man
                }).ToList()
            });

            return Task.FromResult(query);
        }
    }
}