using Features.Breweries.Commands.CreateBrewery;
using Features.Breweries.Commands.DeleteBrewery;
using Features.Breweries.Commands.UpdateBrewery;
using Features.Breweries.Dtos;
using Features.Breweries.Queries.GetAllBreweries;
using Features.Breweries.Queries.GetAllBreweryLocations;
using Features.Breweries.Queries.GetBreweryById;
using Features.Breweries.Queries.GetBreweryLocationsWithinRange;
using MediatR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Shared.Contracts;
namespace Features.Breweries.Controllers;
///
/// Provides HTTP endpoints for reading and managing brewery posts.
///
///
/// Requests require JWT authentication unless the endpoint allows anonymous access.
///
///
[ApiController]
[Route("api/[controller]")]
[Authorize(AuthenticationSchemes = "JWT")]
public class BreweryController(IMediator mediator) : ControllerBase
{
///
/// Returns the brewery post identified by .
///
/// This endpoint permits anonymous access.
///
/// A successful response containing the post, or 404 Not Found when it is absent.
///
[AllowAnonymous]
[HttpGet("{id:guid}")]
public async Task>> GetById(Guid id)
{
BreweryDto? brewery = await mediator.Send(new GetBreweryByIdQuery(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 = brewery,
}
);
}
///
/// Returns brewery posts in reverse chronological order.
///
///
/// Limits the number of returned posts; leaves it unlimited.
///
///
/// Skips this many posts; means none.
///
/// This endpoint permits anonymous access.
[AllowAnonymous]
[HttpGet]
public async Task>>> GetAll(
[FromQuery] int? limit,
[FromQuery] int? offset
)
{
IEnumerable breweries = await mediator.Send(
new GetAllBreweriesQuery(limit, offset)
);
return Ok(
new ResponseBody>
{
Message = "Breweries retrieved successfully.",
Payload = breweries,
}
);
}
///
/// Returns all brewery posts with an associated location.
///
/// This endpoint permits anonymous access.
[AllowAnonymous]
[HttpGet("locations")]
public async Task<
ActionResult>>
> GetAllLocations()
{
IEnumerable breweries = await mediator.Send(
new GetAllBreweryLocationsQuery()
);
return Ok(
new ResponseBody>
{
Message = "Brewery locations retrieved successfully.",
Payload = breweries,
}
);
}
///
/// Returns located brewery posts within the requested radius, ordered by proximity.
///
///
/// Identifies the origin latitude in decimal degrees.
///
///
/// Identifies the origin longitude in decimal degrees.
///
///
/// Sets the maximum distance from the origin in metres.
///
/// This endpoint permits anonymous access.
[AllowAnonymous]
[HttpGet("locations/nearby")]
public async Task<
ActionResult>>
> GetLocationsWithinRange(
[FromQuery] double latitude,
[FromQuery] double longitude,
[FromQuery] double rangeInMetres
)
{
IEnumerable breweries = await mediator.Send(
new GetBreweryLocationsWithinRangeQuery(latitude, longitude, rangeInMetres)
);
return Ok(
new ResponseBody>
{
Message = "Brewery locations retrieved successfully.",
Payload = breweries,
}
);
}
///
/// Creates a brewery post for the authenticated user.
///
/// A 201 Created response containing the new post.
[HttpPost]
public async Task>> Create(
[FromBody] CreateBreweryRequest request
)
{
BreweryDto brewery = await mediator.Send(
new CreateBreweryCommand(
User.GetAuthenticatedUserId(),
request.BreweryName,
request.Description,
request.Location
)
);
return Created(
$"/api/brewery/{brewery.BreweryPostId}",
new ResponseBody
{
Message = "Brewery created successfully.",
Payload = brewery,
}
);
}
///
/// Updates a brewery post owned by the authenticated user.
///
///
/// Must equal the brewery post identifier in .
///
///
/// A successful response containing the updated post, or an error for an invalid ID,
/// missing resource, or stale row version.
///
[HttpPut("{id:guid}")]
public async Task>> Update(
Guid id,
[FromBody] UpdateBreweryRequest request
)
{
if (request.BreweryPostId != id)
return BadRequest(new ResponseBody { Message = "Route ID does not match payload ID." });
BreweryDto breweryUpdated = await mediator.Send(
new UpdateBreweryCommand(
request.BreweryPostId,
User.GetAuthenticatedUserId(),
request.RowVersion,
request.BreweryName,
request.Description,
request.Location
)
);
return Ok(
new ResponseBody
{
Message = "Brewery updated successfully.",
Payload = breweryUpdated,
}
);
}
///
/// Deletes a brewery post owned by the authenticated user.
///
///
/// A confirmation response, or 404 Not Found if the post is absent.
///
[HttpDelete("{id:guid}")]
public async Task> Delete(Guid id)
{
await mediator.Send(new DeleteBreweryCommand(id, User.GetAuthenticatedUserId()));
return Ok(new ResponseBody { Message = "Brewery deleted successfully." });
}
}