using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using RobotNet10.MapEditor.Shared.DTOs.Node;
using RobotNet10.MapEditor.Shared.DTOs.Requests;
using RobotNet10.MapEditor.Shared.DTOs.Responses;
using RobotNet10.MapManager.Services;
namespace RobotNet10.MapManager.Controllers;
///
/// Controller for managing nodes
///
[ApiController]
[Route("api/nodes")]
[Authorize]
public class NodesController(
INodeService nodeService,
ILogger logger) : ControllerBase
{
private readonly INodeService _nodeService = nodeService;
private readonly ILogger _logger = logger;
///
/// Get all nodes for a layout level
///
/// Layout level ID
/// List of nodes with vehicle properties
[HttpGet("level/{layoutLevelId}")]
[ProducesResponseType(typeof(List), 200)]
public async Task>> GetNodesByLevel(Guid layoutLevelId)
{
var nodes = await _nodeService.GetNodesByLevelAsync(layoutLevelId, includeVehicleProperties: true);
var dtos = nodes.Select(MapToDto).ToList();
return Ok(dtos);
}
///
/// Get node by ID
///
/// Node database ID
/// Node details with vehicle properties
[HttpGet("{nodeId}")]
[ProducesResponseType(typeof(NodeDto), 200)]
[ProducesResponseType(404)]
public async Task> GetNode(Guid nodeId)
{
var node = await _nodeService.GetByIdAsync(nodeId, includeVehicleProperties: true);
if (node == null)
{
return NotFound(CreateErrorResponse($"Node with ID '{nodeId}' not found", "NODE_NOT_FOUND"));
}
return Ok(MapToDto(node));
}
///
/// Update node
///
/// Node database ID
/// Update request
/// Updated node
[HttpPut("{nodeId}")]
[ProducesResponseType(typeof(NodeDto), 200)]
[ProducesResponseType(400)]
[ProducesResponseType(404)]
public async Task> UpdateNode(
Guid nodeId,
[FromBody] UpdateNodeRequest request)
{
try
{
var node = await _nodeService.UpdateAsync(nodeId, request);
return Ok(MapToDto(node));
}
catch (InvalidOperationException ex)
{
if (_logger.IsEnabled(LogLevel.Warning)) _logger.LogWarning(ex, "Failed to update node: {NodeId}", nodeId);
if (ex.Message.Contains("not found"))
return NotFound(CreateErrorResponse(ex.Message, "NODE_NOT_FOUND"));
return BadRequest(CreateErrorResponse(ex.Message, "VALIDATION_ERROR"));
}
}
// Helper method to map entity to DTO
private static NodeDto MapToDto(Data.Node node)
{
return new NodeDto
{
Id = node.Id,
LevelId = node.LevelId,
NodeId = node.NodeId,
NodeName = node.NodeName,
NodeDescription = node.NodeDescription,
MapId = node.MapId,
X = node.X,
Y = node.Y,
VehicleProperties = node.VehicleProperties?.Select(vp => new NodeVehiclePropertyDto
{
Id = vp.Id,
NodeId = vp.NodeId,
VehicleTypeId = vp.VehicleTypeId,
VehicleTypeIdString = vp.VehicleType?.VehicleTypeId,
Theta = vp.Theta,
Actions = vp.Actions,
AllowedDeviationXY = vp.AllowedDeviationXY,
AllowedDeviationTheta = vp.AllowedDeviationTheta
}).ToList()
};
}
private static ErrorResponseDto CreateErrorResponse(
string error,
string? errorCode = null,
Dictionary? details = null)
{
return new ErrorResponseDto
{
Error = error,
ErrorCode = errorCode,
Details = details
};
}
}