Clear        


                
                    using CORE.APP.Models;
using CORE.APP.Services;
using CORE.APP.Services.HTTP;
using MediatR;
using Microsoft.EntityFrameworkCore;
using System.Text.Json.Serialization;
using Users.APP.Domain;

namespace Users.APP.Features.Users
{
    /// <summary>
    /// Request object for querying user locations, including API URLs for countries and cities.
    /// </summary>
    public class UserLocationQueryRequest : Request, IRequest<List<UserLocationQueryResponse>>
    {
        //This property is ignored during JSON serialization therefore will not be assigned with the request, will be assigned at the controller's action.
        [JsonIgnore]
        public string CountriesApiUrl { get; set; }

        // This property is ignored during JSON serialization therefore will not be assigned with the request, will be assigned at the controller's action.
        [JsonIgnore]
        public string CitiesApiUrl { get; set; }
    }

    /// <summary>
    /// Response object representing user location details.
    /// </summary>
    public class UserLocationQueryResponse : Response
    {
        public string UserName { get; set; }
        public string FullName { get; set; }
        public string Address { get; set; }
        public int? CountryId { get; set; }
        public string Country { get; set; }
        public int? CityId { get; set; }
        public string City { get; set; }
    }

    /// <summary>
    /// Represents a response from the countries API.
    /// </summary>
    public class CountryApiResponse : Response
    {
        public string CountryName { get; set; }
    }

    /// <summary>
    /// Represents a response from the cities API.
    /// </summary>
    public class CityApiResponse : Response
    {
        public string CityName { get; set; }
    }

    /// <summary>
    /// Handles user location queries by retrieving user data from the database and enriching it with country and city names
    /// fetched from external APIs. Inherits from <see cref="Service{User}"/> for database operations and implements
    /// <see cref="IRequestHandler{UserLocationQueryRequest, List{UserLocationQueryResponse}}"/> for MediatR request handling.
    /// </summary>
    public class UserLocationQueryHandler : Service<User>, IRequestHandler<UserLocationQueryRequest, List<UserLocationQueryResponse>>
    {
        private readonly HttpServiceBase _httpService;

        /// <summary>
        /// Initializes a new instance of the <see cref="UserLocationQueryHandler"/> class.
        /// </summary>
        /// <param name="db">The database context used for querying user data.</param>
        /// <param name="httpService">The HTTP service used to fetch country and city data from external APIs.</param>
        public UserLocationQueryHandler(DbContext db, HttpServiceBase httpService) : base(db)
        {
            _httpService = httpService;
        }

        /// <summary>
        /// Handles the user location query request by fetching user data from the database and enriching it
        /// with country and city names obtained from external APIs.
        /// </summary>
        /// <param name="request">The request containing API URLs for countries and cities.</param>
        /// <param name="cancellationToken">A token to monitor for cancellation requests.</param>
        /// <returns>A list of <see cref="UserLocationQueryResponse"/> objects with user and location details.</returns>
        public async Task<List<UserLocationQueryResponse>> Handle(UserLocationQueryRequest request, CancellationToken cancellationToken)
        {
            // Fetch the list of countries from the external countries API.
            // Each CountryApiResponse contains country details such as Id and CountryName.
            var countries = await _httpService.GetFromJson<CountryApiResponse>(request.CountriesApiUrl, cancellationToken);

            // Fetch the list of cities from the external cities API.
            // Each CityApiResponse contains city details such as Id and CityName.
            var cities = await _httpService.GetFromJson<CityApiResponse>(request.CitiesApiUrl, cancellationToken);

            // Query the users from the database and project them into UserLocationQueryResponse objects.
            // Only user entity properties with city and country ID properties are set at this stage.
            var users = await Query().Select(userEntity => new UserLocationQueryResponse
            {
                Id = userEntity.Id,
                Guid = userEntity.Guid,
                UserName = userEntity.UserName,
                FullName = userEntity.FirstName + " " + userEntity.LastName,
                Address = userEntity.Address,
                CityId = userEntity.CityId,
                CountryId = userEntity.CountryId
            }).ToListAsync(cancellationToken);

            // For each user, enrich the response with the corresponding city and country names
            // by matching the user's CityId and CountryId with the fetched city and country lists from external APIs.
            foreach (var user in users)
            {
                // Find the city name for the user's CityId; set to empty string if not found.
                user.City = cities.FirstOrDefault(city => city.Id == user.CityId) == null ? string.Empty
                    : cities.FirstOrDefault(city => city.Id == user.CityId).CityName;

                // Find the country name for the user's CountryId; set to empty string if not found.
                user.Country = countries.FirstOrDefault(country => country.Id == user.CountryId) == null ? string.Empty
                    : countries.FirstOrDefault(country => country.Id == user.CountryId).CountryName;
            }

            // Return the list of enriched user location responses.
            return users;
        }
    }
}