using LocationsApi.Models; using LocationsApi.Services; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using System.Security.Claims; namespace LocationsApi.Controllers; [ApiController] [Route("api/[controller]")] public class LocationsController : ControllerBase { private readonly LocationService _locations; private readonly UnitTrainingService _units; public LocationsController(LocationService locations, UnitTrainingService units) { _locations = locations; _units = units; } [Authorize(Roles = "USER,SUPER")] [HttpGet] public async Task>> GetAll( [FromQuery] int? minQ, [FromQuery] int? maxQ, [FromQuery] int? minR, [FromQuery] int? maxR) { if (!User.IsInRole("SUPER")) { var username = User.FindFirstValue(ClaimTypes.Name); if (string.IsNullOrWhiteSpace(username)) { return Unauthorized(); } var visible = await _locations.GetVisibleAsync(username); if (minQ.HasValue && maxQ.HasValue && minR.HasValue && maxR.HasValue) { visible = visible .Where(x => x.Q >= minQ.Value && x.Q <= maxQ.Value && x.R >= minR.Value && x.R <= maxR.Value) .ToList(); } return Ok(visible); } var locations = minQ.HasValue && maxQ.HasValue && minR.HasValue && maxR.HasValue ? await _locations.GetRangeAsync(minQ.Value, maxQ.Value, minR.Value, maxR.Value) : await _locations.GetAllAsync(); return Ok(locations.Select(location => LocationResponse.FromLocation(location)).ToList()); } [Authorize(Roles = "USER,SUPER")] [HttpGet("{q:int}/{r:int}")] public async Task> Get(int q, int r) { if (!User.IsInRole("SUPER")) { var username = User.FindFirstValue(ClaimTypes.Name); if (string.IsNullOrWhiteSpace(username)) { return Unauthorized(); } var visibleLocation = await _locations.GetVisibleLocationAsync(username, q, r); return visibleLocation is null ? NotFound() : Ok(visibleLocation); } var location = await _locations.GetAsync(q, r); return location is null ? NotFound() : Ok(LocationResponse.FromLocation(location)); } [Authorize(Roles = "USER,SUPER")] [HttpPost("claim")] public async Task> Claim([FromBody] ClaimLocationRequest request) { var username = User.FindFirstValue(ClaimTypes.Name); if (string.IsNullOrWhiteSpace(username)) { return Unauthorized(); } if (!User.IsInRole("SUPER") && !await _locations.CanSeeAsync(username, request.Q, request.R)) { return NotFound(); } if (!User.IsInRole("SUPER") && !await _locations.IsAdjacentToOwnedAsync(username, request.Q, request.R)) { return BadRequest("Territory claims must be adjacent to controlled territory."); } var existingLocation = await _locations.GetAsync(request.Q, request.R); if (existingLocation is not null && !string.IsNullOrWhiteSpace(existingLocation.OwnerUsername)) { if (string.Equals(existingLocation.OwnerUsername, username, StringComparison.OrdinalIgnoreCase)) { return Ok(LocationResponse.FromLocation(existingLocation)); } return Conflict("Location is already controlled by another player."); } if (!User.IsInRole("SUPER") && !await _units.TryConsumeCompletedScoutAsync(username)) { return BadRequest("A completed scout is required to claim unclaimed territory."); } var location = await _locations.ClaimAsync(request.Q, request.R, username); if (location is null) { return Conflict("Location is already controlled by another player."); } return Ok(LocationResponse.FromLocation(location)); } [Authorize(Roles = "USER,SUPER")] [HttpPost("build")] public async Task> Build([FromBody] BuildLocationRequest request) { var username = User.FindFirstValue(ClaimTypes.Name); if (string.IsNullOrWhiteSpace(username)) { return Unauthorized(); } try { var location = await _locations.BuildAsync(request, username); if (location is null) { return NotFound("Build target must be controlled by the player."); } return Ok(LocationResponse.FromLocation(location)); } catch (InvalidOperationException ex) { return BadRequest(ex.Message); } catch (ArgumentException ex) { return BadRequest(ex.Message); } } [Authorize(Roles = "USER,SUPER")] [HttpPost("assign-worker")] public async Task> AssignWorker([FromBody] AssignWorkerRequest request) { var username = User.FindFirstValue(ClaimTypes.Name); if (string.IsNullOrWhiteSpace(username)) { return Unauthorized(); } var location = await _locations.AssignWorkerAsync(username, request); return location is null ? BadRequest("Select an idle Peasant and a controlled completed building without a worker.") : Ok(LocationResponse.FromLocation(location)); } [Authorize(Roles = "USER,SUPER")] [HttpPost("deassign-worker")] public async Task> DeassignWorker([FromBody] DeassignWorkerRequest request) { var username = User.FindFirstValue(ClaimTypes.Name); if (string.IsNullOrWhiteSpace(username)) { return Unauthorized(); } var location = await _locations.DeassignWorkerAsync(username, request); return location is null ? BadRequest("Select a controlled building with an assigned worker.") : Ok(LocationResponse.FromLocation(location)); } [Authorize(Roles = "USER,SUPER")] [HttpGet("home")] public async Task> GetHome() { var username = User.FindFirstValue(ClaimTypes.Name); if (string.IsNullOrWhiteSpace(username)) { return Unauthorized(); } var home = await _locations.GetHomeAsync(username); return home is null ? NotFound() : Ok(LocationResponse.FromLocation(home)); } [Authorize(Roles = "USER,SUPER")] [HttpPost("home")] public async Task> AssignHome() { var username = User.FindFirstValue(ClaimTypes.Name); if (string.IsNullOrWhiteSpace(username)) { return Unauthorized(); } var home = await _locations.AssignHomeAsync(username); return Ok(LocationResponse.FromLocation(home)); } [Authorize(Roles = "USER,SUPER")] [HttpGet("visible")] public async Task>> GetVisible([FromQuery] int? depth) { var username = User.FindFirstValue(ClaimTypes.Name); if (string.IsNullOrWhiteSpace(username)) { return Unauthorized(); } return Ok(await _locations.GetVisibleAsync(username, depth)); } [Authorize(Roles = "SUPER")] [HttpPut] public async Task> Upsert([FromBody] UpsertLocationRequest request) { var location = await _locations.UpsertAsync(request); return Ok(LocationResponse.FromLocation(location)); } }