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 }; } }