using API.Core.Contracts.Breweries; using Shared.Contracts; using Domain.Entities; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Service.Breweries; namespace API.Core.Controllers; /// /// Provides CRUD endpoints for managing brewery posts. /// /// /// The controller is decorated with [Authorize(AuthenticationSchemes = "JWT")] by default; read endpoints /// ( and ) opt out via [AllowAnonymous]. /// /// Service used to query and mutate brewery post data. [ApiController] [Route("api/[controller]")] [Authorize(AuthenticationSchemes = "JWT")] public class BreweryController(IBreweryService breweryService) : ControllerBase { /// /// Retrieves a single brewery post by its unique identifier. /// /// Allows anonymous access. /// The unique identifier of the brewery post to retrieve. /// /// A 200 OK result wrapping a of if found; /// otherwise a 404 Not Found result wrapping a error message. /// [AllowAnonymous] [HttpGet("{id:guid}")] public async Task>> GetById(Guid id) { var brewery = await breweryService.GetByIdAsync(id); if (brewery is null) return NotFound(new ResponseBody { Message = $"Brewery with ID {id} not found." }); return Ok(new ResponseBody { Message = "Brewery retrieved successfully.", Payload = MapToDto(brewery), }); } /// /// Retrieves a paginated list of brewery posts. /// /// Allows anonymous access. /// The maximum number of brewery posts to return, or null for no limit. /// The number of brewery posts to skip before returning results, or null for no offset. /// A 200 OK result wrapping a of a collection of . [AllowAnonymous] [HttpGet] public async Task>>> GetAll( [FromQuery] int? limit, [FromQuery] int? offset) { var breweries = await breweryService.GetAllAsync(limit, offset); return Ok(new ResponseBody> { Message = "Breweries retrieved successfully.", Payload = breweries.Select(MapToDto), }); } /// /// Creates a new brewery post. /// /// The brewery details to create, including the posting user, name, description, and location. /// /// A 201 Created result wrapping a of the newly created /// if creation succeeds; otherwise a 400 Bad Request result wrapping a error message. /// [HttpPost] public async Task>> Create([FromBody] BreweryCreateDto dto) { var request = new BreweryCreateRequest( dto.PostedById, dto.BreweryName, dto.Description, new BreweryLocationCreateRequest( dto.Location.CityId, dto.Location.AddressLine1, dto.Location.AddressLine2, dto.Location.PostalCode, dto.Location.Coordinates ) ); var result = await breweryService.CreateAsync(request); if (!result.Success) return BadRequest(new ResponseBody { Message = result.Message }); return Created($"/api/brewery/{result.Brewery.BreweryPostId}", new ResponseBody { Message = "Brewery created successfully.", Payload = MapToDto(result.Brewery), }); } /// /// Updates an existing brewery post. /// /// The unique identifier of the brewery post from the route, which must match 's ID. /// The updated brewery details, including the posting user, name, description, and optional location. /// /// A 200 OK result wrapping a of the updated brewery (as a ) /// if the update succeeds; otherwise a 400 Bad Request result wrapping a error message /// (returned when the route ID does not match the payload ID, or when the update itself fails). /// [HttpPut("{id:guid}")] public async Task>> Update(Guid id, [FromBody] BreweryDto dto) { if (dto.BreweryPostId != id) return BadRequest(new ResponseBody { Message = "Route ID does not match payload ID." }); var request = new BreweryUpdateRequest( dto.BreweryPostId, dto.PostedById, dto.BreweryName, dto.Description, dto.Location is null ? null : new BreweryLocationUpdateRequest( dto.Location.BreweryPostLocationId, dto.Location.CityId, dto.Location.AddressLine1, dto.Location.AddressLine2, dto.Location.PostalCode, dto.Location.Coordinates ) ); var result = await breweryService.UpdateAsync(request); if (!result.Success) return BadRequest(new ResponseBody { Message = result.Message }); return Ok(new ResponseBody { Message = "Brewery updated successfully.", Payload = result.Brewery, }); } /// /// Deletes a brewery post. /// /// The unique identifier of the brewery post to delete. /// A 200 OK result wrapping a confirming the deletion. [HttpDelete("{id:guid}")] public async Task> Delete(Guid id) { await breweryService.DeleteAsync(id); return Ok(new ResponseBody { Message = "Brewery deleted successfully." }); } /// /// Maps a domain entity to its representation, /// including its location, if present. /// /// The brewery post entity to map. /// The mapped . private static BreweryDto MapToDto(BreweryPost b) => new() { BreweryPostId = b.BreweryPostId, PostedById = b.PostedById, BreweryName = b.BreweryName, Description = b.Description, CreatedAt = b.CreatedAt, UpdatedAt = b.UpdatedAt, Timer = b.Timer, Location = b.Location is null ? null : new BreweryLocationDto { BreweryPostLocationId = b.Location.BreweryPostLocationId, BreweryPostId = b.Location.BreweryPostId, CityId = b.Location.CityId, AddressLine1 = b.Location.AddressLine1, AddressLine2 = b.Location.AddressLine2, PostalCode = b.Location.PostalCode, Coordinates = b.Location.Coordinates, }, }; }