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