using Extrudex.API.DTOs.Materials; using Extrudex.Domain.Entities; using Extrudex.Infrastructure.Data; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; namespace Extrudex.API.Controllers; /// /// Controller for managing material bases — the core polymer/material type /// (e.g., PLA, PETG, ABS). Enforces consistent material naming across all spools. /// [ApiController] [Route("api/material-bases")] public class MaterialBasesController : ControllerBase { private readonly ExtrudexDbContext _dbContext; private readonly ILogger _logger; public MaterialBasesController( ExtrudexDbContext dbContext, ILogger logger) { _dbContext = dbContext; _logger = logger; } /// /// Gets all material bases ordered by name. /// /// A list of all material bases with their densities. [HttpGet] [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] public async Task>> GetMaterialBases() { _logger.LogDebug("Getting all material bases"); var bases = await _dbContext.MaterialBases .OrderBy(mb => mb.Name) .Select(mb => MapToResponse(mb)) .ToListAsync(); return Ok(bases); } /// /// Gets a specific material base by ID. /// /// The unique identifier of the material base. /// The material base details. [HttpGet("{id:guid}")] [ProducesResponseType(typeof(MaterialBaseResponse), StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task> GetMaterialBase(Guid id) { _logger.LogDebug("Getting material base {Id}", id); var mb = await _dbContext.MaterialBases.FindAsync(id); if (mb is null) { _logger.LogWarning("Material base {Id} not found", id); return NotFound(new { error = $"Material base with ID '{id}' not found." }); } return Ok(MapToResponse(mb)); } /// /// Creates a new material base. /// /// The material base creation request. /// The created material base. [HttpPost] [ProducesResponseType(typeof(MaterialBaseResponse), StatusCodes.Status201Created)] [ProducesResponseType(StatusCodes.Status400BadRequest)] public async Task> CreateMaterialBase( [FromBody] CreateMaterialBaseRequest request) { _logger.LogInformation("Creating material base: {Name}", request.Name); var entity = new MaterialBase { Name = request.Name, DensityGperCm3 = request.DensityGperCm3 }; _dbContext.MaterialBases.Add(entity); await _dbContext.SaveChangesAsync(); var response = MapToResponse(entity); return CreatedAtAction(nameof(GetMaterialBase), new { id = entity.Id }, response); } /// /// Updates an existing material base. /// /// The unique identifier of the material base to update. /// The material base update request. /// The updated material base. [HttpPut("{id:guid}")] [ProducesResponseType(typeof(MaterialBaseResponse), StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesResponseType(StatusCodes.Status400BadRequest)] public async Task> UpdateMaterialBase( Guid id, [FromBody] UpdateMaterialBaseRequest request) { _logger.LogInformation("Updating material base {Id}", id); var entity = await _dbContext.MaterialBases.FindAsync(id); if (entity is null) { _logger.LogWarning("Material base {Id} not found for update", id); return NotFound(new { error = $"Material base with ID '{id}' not found." }); } entity.Name = request.Name; entity.DensityGperCm3 = request.DensityGperCm3; await _dbContext.SaveChangesAsync(); return Ok(MapToResponse(entity)); } /// /// Deletes a material base. /// /// The unique identifier of the material base to delete. [HttpDelete("{id:guid}")] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task DeleteMaterialBase(Guid id) { _logger.LogInformation("Deleting material base {Id}", id); var entity = await _dbContext.MaterialBases.FindAsync(id); if (entity is null) { _logger.LogWarning("Material base {Id} not found for deletion", id); return NotFound(new { error = $"Material base with ID '{id}' not found." }); } _dbContext.MaterialBases.Remove(entity); await _dbContext.SaveChangesAsync(); return NoContent(); } // ── Mapping helper ────────────────────────────────────────── private static MaterialBaseResponse MapToResponse(MaterialBase mb) => new() { Id = mb.Id, Name = mb.Name, DensityGperCm3 = mb.DensityGperCm3, CreatedAt = mb.CreatedAt, UpdatedAt = mb.UpdatedAt }; }