using System.ComponentModel.DataAnnotations;
namespace Extrudex.API.DTOs.Filaments;
///
/// Response DTO for a filament spool — the core inventory unit of Extrudex.
/// Contains all spool details including denormalized material names for display.
///
public class FilamentResponse
{
/// Unique identifier for the filament spool.
public Guid Id { get; set; }
/// Foreign key to the base material.
public Guid MaterialBaseId { get; set; }
/// Name of the base material (e.g., "PLA", "PETG").
public string MaterialBaseName { get; set; } = string.Empty;
/// Foreign key to the material finish.
public Guid MaterialFinishId { get; set; }
/// Name of the material finish (e.g., "Basic", "Matte").
public string MaterialFinishName { get; set; } = string.Empty;
/// Foreign key to the optional material modifier. Null if none.
public Guid? MaterialModifierId { get; set; }
/// Name of the material modifier (e.g., "Carbon Fiber"). Null if none.
public string? MaterialModifierName { get; set; }
/// Brand name (e.g., "Bambu Lab", "Polymaker").
public string Brand { get; set; } = string.Empty;
/// Human-readable color name (e.g., "Fire Engine Red").
public string ColorName { get; set; } = string.Empty;
/// Hex color code (e.g., "#FF0000").
public string ColorHex { get; set; } = string.Empty;
/// Total spool weight in grams when full.
public decimal WeightTotalGrams { get; set; }
/// Current remaining weight in grams.
public decimal WeightRemainingGrams { get; set; }
/// Filament diameter in millimeters. Typically 1.75mm.
public decimal FilamentDiameterMm { get; set; }
/// Manufacturer-assigned serial number. Must be unique.
public string SpoolSerial { get; set; } = string.Empty;
/// Purchase price per spool. Null if not tracked.
public decimal? PurchasePrice { get; set; }
/// Date the spool was purchased or received.
public DateTime? PurchaseDate { get; set; }
/// Whether the spool is currently active and available.
public bool IsActive { get; set; }
/// Timestamp when this record was created (UTC).
public DateTime CreatedAt { get; set; }
/// Timestamp when this record was last updated (UTC).
public DateTime UpdatedAt { get; set; }
///
/// URL to the QR code image for this spool.
/// Encodes a deep link to the spool's detail page.
///
public string QrCodeUrl { get; set; } = string.Empty;
}
///
/// Request DTO for creating a new filament spool.
/// All required fields must be provided. MaterialFinish is required — use "Basic" as the default.
///
public class CreateFilamentRequest
{
/// Foreign key to the base material. Required.
[Required(ErrorMessage = "MaterialBaseId is required.")]
public Guid MaterialBaseId { get; set; }
/// Foreign key to the material finish. Required — default is "Basic".
[Required(ErrorMessage = "MaterialFinishId is required.")]
public Guid MaterialFinishId { get; set; }
/// Foreign key to the optional material modifier. Null if none applies.
public Guid? MaterialModifierId { get; set; }
/// Brand name (e.g., "Bambu Lab", "Polymaker"). Required, max 200 characters.
[Required(ErrorMessage = "Brand is required.")]
[StringLength(200, MinimumLength = 1, ErrorMessage = "Brand must be between 1 and 200 characters.")]
public string Brand { get; set; } = string.Empty;
/// Human-readable color name (e.g., "Fire Engine Red"). Required, max 200 characters.
[Required(ErrorMessage = "ColorName is required.")]
[StringLength(200, MinimumLength = 1, ErrorMessage = "ColorName must be between 1 and 200 characters.")]
public string ColorName { get; set; } = string.Empty;
/// Hex color code (e.g., "#FF0000"). Required, must be valid 7-char hex.
[Required(ErrorMessage = "ColorHex is required.")]
[RegularExpression(@"^#[0-9A-Fa-f]{6}$", ErrorMessage = "ColorHex must be a valid hex color code (e.g., #FF0000).")]
[StringLength(7, MinimumLength = 7, ErrorMessage = "ColorHex must be exactly 7 characters (e.g., #FF0000).")]
public string ColorHex { get; set; } = string.Empty;
/// Total spool weight in grams when full. Must be greater than zero.
[Required(ErrorMessage = "WeightTotalGrams is required.")]
[Range(0.01, 100000, ErrorMessage = "Total weight must be between 0.01 and 100,000 grams.")]
public decimal WeightTotalGrams { get; set; }
/// Current remaining weight in grams. Must be non-negative.
[Required(ErrorMessage = "WeightRemainingGrams is required.")]
[Range(0, 100000, ErrorMessage = "Remaining weight must be between 0 and 100,000 grams.")]
public decimal WeightRemainingGrams { get; set; }
/// Filament diameter in mm. Defaults to 1.75. Must be greater than zero.
[Range(0.1, 10.0, ErrorMessage = "Filament diameter must be between 0.1 and 10.0 mm.")]
public decimal FilamentDiameterMm { get; set; } = 1.75m;
/// Manufacturer-assigned serial number. Must be unique, max 200 characters.
[Required(ErrorMessage = "SpoolSerial is required.")]
[StringLength(200, MinimumLength = 1, ErrorMessage = "SpoolSerial must be between 1 and 200 characters.")]
public string SpoolSerial { get; set; } = string.Empty;
/// Optional purchase price per spool. Must be non-negative if provided.
[Range(0, 1000000, ErrorMessage = "Purchase price must be between 0 and 1,000,000.")]
public decimal? PurchasePrice { get; set; }
/// Optional purchase date. Must be a valid date if provided.
public DateTime? PurchaseDate { get; set; }
/// Whether the spool is active. Defaults to true.
public bool IsActive { get; set; } = true;
}
///
/// Request DTO for updating an existing filament spool.
/// All required fields must be provided for a full update.
///
public class UpdateFilamentRequest
{
/// Foreign key to the base material. Required.
[Required(ErrorMessage = "MaterialBaseId is required.")]
public Guid MaterialBaseId { get; set; }
/// Foreign key to the material finish. Required.
[Required(ErrorMessage = "MaterialFinishId is required.")]
public Guid MaterialFinishId { get; set; }
/// Foreign key to the optional material modifier. Null if none applies.
public Guid? MaterialModifierId { get; set; }
/// Brand name. Required, max 200 characters.
[Required(ErrorMessage = "Brand is required.")]
[StringLength(200, MinimumLength = 1, ErrorMessage = "Brand must be between 1 and 200 characters.")]
public string Brand { get; set; } = string.Empty;
/// Human-readable color name. Required, max 200 characters.
[Required(ErrorMessage = "ColorName is required.")]
[StringLength(200, MinimumLength = 1, ErrorMessage = "ColorName must be between 1 and 200 characters.")]
public string ColorName { get; set; } = string.Empty;
/// Hex color code (e.g., "#FF0000"). Required, must be valid 7-char hex.
[Required(ErrorMessage = "ColorHex is required.")]
[RegularExpression(@"^#[0-9A-Fa-f]{6}$", ErrorMessage = "ColorHex must be a valid hex color code (e.g., #FF0000).")]
[StringLength(7, MinimumLength = 7, ErrorMessage = "ColorHex must be exactly 7 characters (e.g., #FF0000).")]
public string ColorHex { get; set; } = string.Empty;
/// Total spool weight in grams when full. Must be greater than zero.
[Required(ErrorMessage = "WeightTotalGrams is required.")]
[Range(0.01, 100000, ErrorMessage = "Total weight must be between 0.01 and 100,000 grams.")]
public decimal WeightTotalGrams { get; set; }
/// Current remaining weight in grams. Must be non-negative.
[Required(ErrorMessage = "WeightRemainingGrams is required.")]
[Range(0, 100000, ErrorMessage = "Remaining weight must be between 0 and 100,000 grams.")]
public decimal WeightRemainingGrams { get; set; }
/// Filament diameter in mm. Must be greater than zero.
[Range(0.1, 10.0, ErrorMessage = "Filament diameter must be between 0.1 and 10.0 mm.")]
public decimal FilamentDiameterMm { get; set; } = 1.75m;
/// Manufacturer-assigned serial number. Must be unique, max 200 characters.
[Required(ErrorMessage = "SpoolSerial is required.")]
[StringLength(200, MinimumLength = 1, ErrorMessage = "SpoolSerial must be between 1 and 200 characters.")]
public string SpoolSerial { get; set; } = string.Empty;
/// Optional purchase price per spool. Must be non-negative if provided.
[Range(0, 1000000, ErrorMessage = "Purchase price must be between 0 and 1,000,000.")]
public decimal? PurchasePrice { get; set; }
/// Optional purchase date.
public DateTime? PurchaseDate { get; set; }
/// Whether the spool is active.
public bool IsActive { get; set; } = true;
}