Clear        


                
                    #nullable disable
using CORE.APP.Models;
using MediatR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Users.APP.Features.Users;

//Generated from Custom Microservices Template.
namespace Users.API.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class UsersController : ControllerBase
    {
        private readonly ILogger<UsersController> _logger;
        private readonly IMediator _mediator;

        // Constructor: injects logger to log the errors to Kestrel Console or Output Window and mediator
        public UsersController(ILogger<UsersController> logger, IMediator mediator)
        {
            _logger = logger;
            _mediator = mediator;
        }

        // GET: api/Users
        [HttpGet]
        // Way 1:
        //[Authorize(Roles = "Admin,User")] // Only authenticated users with role Admin or User can execute this action.
        // Way 2: since we have only 2 roles Admin and User, we can use Authorize to check auhenticated users without defining roles.
        [Authorize]
        public async Task<IActionResult> Get()
        {
            try
            {
                // Send a query request to get query response
                var response = await _mediator.Send(new UserQueryRequest());
                // Convert the query response to a list
                var list = await response.ToListAsync();
                // If there are items, return them with 200 OK
                if (list.Any())
                    return Ok(list);
                // If no items found, return 204 No Content
                return NoContent();
            }
            catch (Exception exception)
            {
                // Log the exception
                _logger.LogError("UsersGet Exception: " + exception.Message);
                // Return 500 Internal Server Error with an error command response with message
                return StatusCode(StatusCodes.Status500InternalServerError, new CommandResponse(false, "An exception occured during UsersGet."));
            }
        }

        // GET: api/Users/5
        [HttpGet("{id}")]
        [Authorize(Roles = "Admin")] // Only authenticated users with role Admin can execute this action.
        public async Task<IActionResult> Get(int id)
        {
            try
            {
                // Send a query request to get query response
                var response = await _mediator.Send(new UserQueryRequest());
                // Find the item with the given id
                var item = await response.SingleOrDefaultAsync(r => r.Id == id);
                // If item found, return it with 200 OK
                if (item is not null)
                    return Ok(item);
                // If item not found, return 204 No Content
                return NoContent();
            }
            catch (Exception exception)
            {
                // Log the exception
                _logger.LogError("UsersGetById Exception: " + exception.Message);
                // Return 500 Internal Server Error with an error command response with message
                return StatusCode(StatusCodes.Status500InternalServerError, new CommandResponse(false, "An exception occured during UsersGetById."));
            }
        }

        // POST: api/Users
        [HttpPost]
        [Authorize(Roles = "Admin")] // Only authenticated users with role Admin can execute this action.
        public async Task<IActionResult> Post(UserCreateRequest request)
        {
            try
            {
                // Check if the request model is valid through data annotations
                if (ModelState.IsValid)
                {
                    // Send the create request
                    var response = await _mediator.Send(request);
                    // If creation is successful, return 200 OK with success command response
                    if (response.IsSuccessful)
                    {
                        //return CreatedAtAction(nameof(Get), new { id = response.Id }, response);
                        return Ok(response);
                    }
                    // If creation failed, add error command response message to model state
                    ModelState.AddModelError("UsersPost", response.Message);
                }
                // Return 400 Bad Request with all data annotation validation error messages and the error command response message if added seperated by |
                return BadRequest(new CommandResponse(false, string.Join("|", ModelState.Values.SelectMany(v => v.Errors).Select(e => e.ErrorMessage))));
            }
            catch (Exception exception)
            {
                // Log the exception
                _logger.LogError("UsersPost Exception: " + exception.Message);
                // Return 500 Internal Server Error with an error command response with message
                return StatusCode(StatusCodes.Status500InternalServerError, new CommandResponse(false, "An exception occured during UsersPost."));
            }
        }

        // PUT: api/Users
        [HttpPut]
        [Authorize(Roles = "Admin")] // Only authenticated users with role Admin can execute this action.
        public async Task<IActionResult> Put(UserUpdateRequest request)
        {
            try
            {
                // Check if the request model is valid through data annotations
                if (ModelState.IsValid)
                {
                    // Send the update request
                    var response = await _mediator.Send(request);
                    // If update is successful, return 200 OK with success command response
                    if (response.IsSuccessful)
                    {
                        //return NoContent();
                        return Ok(response);
                    }
                    // If update failed, add error command response message to model state
                    ModelState.AddModelError("UsersPut", response.Message);
                }
                // Return 400 Bad Request with all data annotation validation error messages and the error command response message if added seperated by |
                return BadRequest(new CommandResponse(false, string.Join("|", ModelState.Values.SelectMany(v => v.Errors).Select(e => e.ErrorMessage))));
            }
            catch (Exception exception)
            {
                // Log the exception
                _logger.LogError("UsersPut Exception: " + exception.Message);
                // Return 500 Internal Server Error with an error command response with message
                return StatusCode(StatusCodes.Status500InternalServerError, new CommandResponse(false, "An exception occured during UsersPut."));
            }
        }

        // DELETE: api/Users/5
        [HttpDelete("{id}")]
        [Authorize(Roles = "Admin")] // Only authenticated users with role Admin can execute this action.
        public async Task<IActionResult> Delete(int id)
        {
            try
            {
                // Send the delete request
                var response = await _mediator.Send(new UserDeleteRequest() { Id = id });
                // If delete is successful, return 200 OK with success command response
                if (response.IsSuccessful)
                {
                    //return NoContent();
                    return Ok(response);
                }
                // If delete failed, add error command response message to model state
                ModelState.AddModelError("UsersDelete", response.Message);
                // Return 400 Bad Request with the error command response message
                return BadRequest(new CommandResponse(false, string.Join("|", ModelState.Values.SelectMany(v => v.Errors).Select(e => e.ErrorMessage))));
            }
            catch (Exception exception)
            {
                // Log the exception
                _logger.LogError("UsersDelete Exception: " + exception.Message);
                // Return 500 Internal Server Error with an error command response with message
                return StatusCode(StatusCodes.Status500InternalServerError, new CommandResponse(false, "An exception occured during UsersDelete."));
            }
        }



        /// <summary>
        /// Returns a response with filtered Users data according to the request.
        /// The post request can be sent to the route api/Users/GetFiltered.
        /// </summary>
        /// <param name="request">A user query request to filter Users data.</param>
        /// <returns>A success response with filtered user query response data if any, otherwise no content response.</returns>
        [HttpPost("[action]")]
        // Way 1:
        //[Authorize(Roles = "Admin,User")] // Only authenticated users with role Admin or User can execute this action.
        // Way 2: since we have only 2 roles Admin and User, we can use Authorize to check auhenticated users without defining roles.
        [Authorize]
        public async Task<IActionResult> GetFiltered(UserQueryRequest request)
        {
            var response = await _mediator.Send(request);
            var list = await response.ToListAsync();
            if (list.Any())
                return Ok(list);
            return NoContent();
        }



        /// <summary>
        /// Retrieves a list of user location data, including countries and cities, by calling external APIs.
        /// The GET request can be sent to the route api/Users/GetUserLocations.
        /// </summary>
        /// <remarks>
        /// This action sends a <see cref="UserLocationQueryRequest"/> to the mediator, which fetches location data
        /// from the specified Countries and Cities API endpoints. The response is returned as an HTTP 200 OK result
        /// containing the list of locations.
        /// </remarks>
        /// <returns>
        /// An <see cref="IActionResult"/> containing the list of user locations if successful.
        /// </returns>
        [HttpGet("[action]")]
        [Authorize] // Only authenticated users can execute this action.
        public async Task<IActionResult> GetUserLocations()
        {
            var list = await _mediator.Send(new UserLocationQueryRequest
            {
                // Gateway Countries API URL
                CountriesApiUrl = "https://localhost:7237/api/countries",

                // Gateway Cities API URL
                CitiesApiUrl = "https://localhost:7237/api/cities"
            });
            return Ok(list);
        }
    }
}