using API.Core.Contracts.Breweries;
using API.Core.Contracts.Common;
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,
},
};
}