using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using WondersAPI.Data;
using WondersAPI.Models;
namespace Ghaymah.WondersAPI.Controllers
{
///
/// API controller to manage Wonders (CRUD + Random).
///
[ApiController]
[Route("api/[controller]")]
public class WondersController : ControllerBase
{
private readonly AppDbContext _context;
private readonly ILogger _logger;
public WondersController(AppDbContext context, ILogger logger)
{
_context = context;
_logger = logger;
}
// -------------------- GET ALL --------------------
///
/// Get all wonders.
///
/// List of all wonders.
[HttpGet]
[ProducesResponseType(typeof(IEnumerable), 200)]
public async Task GetAllWonders()
{
var wonders = await FetchAllWonders();
LogFetchedWonders(wonders.Count);
return Ok(wonders);
}
private async Task> FetchAllWonders() =>
await _context.Wonders.ToListAsync();
private void LogFetchedWonders(int count) =>
_logger.LogInformation("Fetched {Count} wonders from database", count);
// -------------------- GET BY ID --------------------
///
/// Get a specific wonder by its ID.
///
/// The ID of the wonder.
/// The wonder with the specified ID.
[HttpGet("{id}")]
[ProducesResponseType(typeof(Wonder), 200)]
[ProducesResponseType(404)]
public async Task GetWonderById(int wonderId)
{
var wonder = await FindWonderOrNotFound(wonderId);
if (wonder is null) return NotFound(new { message = $"Wonder with ID {wonderId} not found" });
return Ok(wonder);
}
private async Task FindWonderOrNotFound(int wonderId) =>
await _context.Wonders.FindAsync(wonderId);
// -------------------- CREATE --------------------
///
/// Create a new wonder.
///
/// The wonder to create.
/// The created wonder.
[HttpPost]
[ProducesResponseType(typeof(Wonder), 201)]
public async Task CreateWonder([FromBody] Wonder newWonder) =>
await SaveNewWonder(newWonder);
private async Task SaveNewWonder(Wonder wonder)
{
_context.Wonders.Add(wonder);
await _context.SaveChangesAsync();
LogCreatedWonder(wonder.Name);
return CreatedAtAction(nameof(GetWonderById), new { wonderId = wonder.Id }, wonder);
}
private void LogCreatedWonder(string name) =>
_logger.LogInformation("Created new wonder: {Name}", name);
// -------------------- UPDATE --------------------
///
/// Update an existing wonder.
///
/// The ID of the wonder to update.
/// The updated wonder data.
[HttpPut("{id}")]
[ProducesResponseType(204)]
[ProducesResponseType(404)]
public async Task UpdateWonder(int wonderId, [FromBody] Wonder updatedWonder)
{
var existingWonder = await FindWonderOrNotFound(wonderId);
if (existingWonder is null) return NotFound();
return await SaveUpdatedWonder(existingWonder, updatedWonder);
}
private async Task SaveUpdatedWonder(Wonder target, Wonder source)
{
CopyWonderValues(target, source);
await _context.SaveChangesAsync();
LogUpdatedWonder(target.Id);
return NoContent();
}
private void CopyWonderValues(Wonder target, Wonder source)
{
target.Name = source.Name;
target.Country = source.Country;
target.Era = source.Era;
target.Type = source.Type;
target.Description = source.Description;
target.DiscoveryYear = source.DiscoveryYear;
}
private void LogUpdatedWonder(int wonderId) =>
_logger.LogInformation("Updated wonder with ID {Id}", wonderId);
// -------------------- DELETE --------------------
///
/// Delete a wonder by ID.
///
/// The ID of the wonder to delete.
[HttpDelete("{id}")]
[ProducesResponseType(204)]
[ProducesResponseType(404)]
public async Task DeleteWonder(int wonderId)
{
var wonder = await FindWonderOrNotFound(wonderId);
if (wonder is null) return NotFound();
await RemoveWonder(wonder);
return NoContent();
}
private async Task RemoveWonder(Wonder wonder)
{
_context.Wonders.Remove(wonder);
await _context.SaveChangesAsync();
LogDeletedWonder(wonder.Id);
}
private void LogDeletedWonder(int wonderId) =>
_logger.LogInformation("Deleted wonder with ID {Id}", wonderId);
// -------------------- GET RANDOM --------------------
///
/// Get a random wonder.
///
/// A randomly selected wonder.
[HttpGet("random")]
[ProducesResponseType(typeof(Wonder), 200)]
[ProducesResponseType(404)]
public async Task GetRandomWonder()
{
var allWonders = await FetchAllWonders();
if (!allWonders.Any()) return NotFound();
var randomWonder = SelectRandomWonder(allWonders);
LogRandomWonder(randomWonder.Name);
return Ok(randomWonder);
}
private Wonder SelectRandomWonder(List wonders) =>
wonders[new Random().Next(wonders.Count)];
private void LogRandomWonder(string name) =>
_logger.LogInformation("Returned random wonder: {Name}", name);
}
}