using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using RobotNet10.MapEditor.Shared.DTOs.VehicleType;
using RobotNet10.MapEditor.Shared.DTOs.Requests;
using RobotNet10.MapEditor.Shared.DTOs.Responses;
using RobotNet10.MapManager.Services;
namespace RobotNet10.MapManager.Controllers;
///
/// Controller for managing vehicle types
///
[ApiController]
[Route("api/vehicles")]
[Authorize]
public class VehiclesManagerController(
IVehicleTypeService vehicleTypeService,
ILogger logger) : ControllerBase
{
private readonly IVehicleTypeService _vehicleTypeService = vehicleTypeService;
private readonly ILogger _logger = logger;
///
/// Create a new vehicle type
///
/// Vehicle type creation request
/// Created vehicle type
[HttpPost]
[ProducesResponseType(typeof(VehicleTypeDto), 201)]
[ProducesResponseType(400)]
public async Task> CreateVehicleType([FromBody] CreateVehicleTypeRequest request)
{
try
{
var vehicleType = await _vehicleTypeService.CreateAsync(
request.VehicleTypeId,
request.VehicleTypeName,
request.Description,
request.Specifications,
request.Actions);
var dto = MapToDto(vehicleType);
return CreatedAtAction(
nameof(GetVehicleType),
new { vehicleTypeId = vehicleType.Id },
dto);
}
catch (InvalidOperationException ex)
{
_logger.LogWarning(ex, "Failed to create vehicle type: {VehicleTypeId}", request.VehicleTypeId);
var errorCode = ex.Message.Contains("already exists")
? "VEHICLE_TYPE_ALREADY_EXISTS"
: "VALIDATION_ERROR";
return BadRequest(CreateErrorResponse(ex.Message, errorCode));
}
}
///
/// Get all vehicle types
///
/// Optional filter by active status
/// List of vehicle types
[HttpGet]
[ProducesResponseType(typeof(List), 200)]
public async Task>> GetAllVehicleTypes([FromQuery] bool? isActive)
{
List vehicleTypes;
if (isActive.HasValue)
{
vehicleTypes = await _vehicleTypeService.GetByActiveStatusAsync(isActive.Value);
}
else
{
vehicleTypes = await _vehicleTypeService.GetAllAsync();
}
var dtos = vehicleTypes.Select(MapToDto).ToList();
return Ok(dtos);
}
///
/// Get vehicle type by database ID
///
/// Vehicle type database ID
/// Vehicle type details
[HttpGet("{vehicleTypeId}")]
[ProducesResponseType(typeof(VehicleTypeDto), 200)]
[ProducesResponseType(404)]
public async Task> GetVehicleType(Guid vehicleTypeId)
{
var vehicleType = await _vehicleTypeService.GetByIdAsync(vehicleTypeId);
if (vehicleType == null)
{
return NotFound(CreateErrorResponse(
$"Vehicle type with ID '{vehicleTypeId}' not found",
"VEHICLE_TYPE_NOT_FOUND"));
}
return Ok(MapToDto(vehicleType));
}
///
/// Get vehicle type by VehicleTypeId string
///
/// Vehicle type identifier string (e.g., "AMR-T800")
/// Vehicle type details
[HttpGet("vehicleTypeId/{vehicleTypeId}")]
[ProducesResponseType(typeof(VehicleTypeDto), 200)]
[ProducesResponseType(404)]
public async Task> GetVehicleTypeByStringId(string vehicleTypeId)
{
var vehicleType = await _vehicleTypeService.GetByVehicleTypeIdAsync(vehicleTypeId);
if (vehicleType == null)
{
return NotFound(CreateErrorResponse(
$"Vehicle type with VehicleTypeId '{vehicleTypeId}' not found",
"VEHICLE_TYPE_NOT_FOUND"));
}
return Ok(MapToDto(vehicleType));
}
///
/// Search vehicle types by query string
/// Searches in VehicleTypeId and VehicleTypeName (case-insensitive)
///
/// Search query
/// List of matching vehicle types
[HttpGet("search")]
[ProducesResponseType(typeof(List), 200)]
public async Task>> SearchVehicleTypes([FromQuery] string query)
{
if (string.IsNullOrWhiteSpace(query))
{
return BadRequest(CreateErrorResponse(
"Query parameter is required",
"VALIDATION_ERROR"));
}
var vehicleTypes = await _vehicleTypeService.SearchAsync(query);
var dtos = vehicleTypes.Select(MapToDto).ToList();
return Ok(dtos);
}
///
/// Get usage information for a vehicle type
///
/// Vehicle type database ID
/// Usage information
[HttpGet("{id}/usage")]
[ProducesResponseType(typeof(VehicleTypeUsageInfoDto), 200)]
[ProducesResponseType(404)]
public async Task> GetVehicleTypeUsage(Guid id)
{
try
{
var usageInfo = await _vehicleTypeService.GetUsageInfoAsync(id);
var dto = MapUsageInfoToDto(usageInfo);
return Ok(dto);
}
catch (InvalidOperationException ex)
{
_logger.LogWarning(ex, "Failed to get usage info for vehicle type: {Id}", id);
return NotFound(CreateErrorResponse(ex.Message, "VEHICLE_TYPE_NOT_FOUND"));
}
}
///
/// Update vehicle type
///
/// Vehicle type database ID
/// Update request
/// Updated vehicle type
[HttpPut("{vehicleTypeId}")]
[ProducesResponseType(typeof(VehicleTypeDto), 200)]
[ProducesResponseType(404)]
public async Task> UpdateVehicleType(
Guid vehicleTypeId,
[FromBody] UpdateVehicleTypeRequest request)
{
try
{
var vehicleType = await _vehicleTypeService.UpdateAsync(
vehicleTypeId,
request.VehicleTypeName,
request.Description,
request.Specifications,
request.Actions,
request.IsActive);
return Ok(MapToDto(vehicleType));
}
catch (InvalidOperationException ex)
{
if (_logger.IsEnabled(LogLevel.Warning)) _logger.LogWarning(ex, "Failed to update vehicle type: {VehicleTypeId}", vehicleTypeId);
return NotFound(CreateErrorResponse(ex.Message, "VEHICLE_TYPE_NOT_FOUND"));
}
}
///
/// Delete vehicle type
///
/// Vehicle type database ID
/// No content on success
[HttpDelete("{vehicleTypeId}")]
[ProducesResponseType(204)]
[ProducesResponseType(404)]
[ProducesResponseType(400)]
public async Task DeleteVehicleType(Guid vehicleTypeId)
{
try
{
var deleted = await _vehicleTypeService.DeleteAsync(vehicleTypeId);
if (!deleted)
{
return NotFound(CreateErrorResponse(
$"Vehicle type with ID '{vehicleTypeId}' not found",
"VEHICLE_TYPE_NOT_FOUND"));
}
return NoContent();
}
catch (InvalidOperationException ex)
{
if (_logger.IsEnabled(LogLevel.Warning)) _logger.LogWarning(ex, "Failed to delete vehicle type: {VehicleTypeId}", vehicleTypeId);
var errorCode = ex.Message.Contains("referenced")
? "VEHICLE_TYPE_IN_USE"
: "VALIDATION_ERROR";
var details = new Dictionary();
if (errorCode == "VEHICLE_TYPE_IN_USE")
{
// Try to get usage info for details
try
{
var usageInfo = await _vehicleTypeService.GetUsageInfoAsync(vehicleTypeId);
details["nodePropertiesCount"] = usageInfo.NodePropertiesCount;
details["edgePropertiesCount"] = usageInfo.EdgePropertiesCount;
details["totalUsageCount"] = usageInfo.TotalUsageCount;
}
catch
{
// Ignore if we can't get usage info
}
}
return BadRequest(CreateErrorResponse(ex.Message, errorCode, details));
}
}
// Helper method to map entity to DTO
private static VehicleTypeDto MapToDto(Data.VehicleType vehicleType)
{
return new VehicleTypeDto
{
Id = vehicleType.Id,
VehicleTypeId = vehicleType.VehicleTypeId,
VehicleTypeName = vehicleType.VehicleTypeName,
Description = vehicleType.Description,
Specifications = vehicleType.Specifications,
Actions = vehicleType.Actions,
IsActive = vehicleType.IsActive,
CreatedDate = vehicleType.CreatedDate
};
}
// Helper method to map usage info to DTO
private static VehicleTypeUsageInfoDto MapUsageInfoToDto(VehicleTypeUsageInfo usageInfo)
{
return new VehicleTypeUsageInfoDto
{
VehicleTypeId = usageInfo.VehicleTypeId,
VehicleTypeIdString = usageInfo.VehicleTypeIdString,
VehicleTypeName = usageInfo.VehicleTypeName,
NodePropertiesCount = usageInfo.NodePropertiesCount,
EdgePropertiesCount = usageInfo.EdgePropertiesCount,
TotalUsageCount = usageInfo.TotalUsageCount,
CanDelete = usageInfo.CanDelete
};
}
// Helper method to create error response
private static ErrorResponseDto CreateErrorResponse(
string error,
string? errorCode = null,
Dictionary? details = null)
{
return new ErrorResponseDto
{
Error = error,
ErrorCode = errorCode,
Details = details
};
}
}