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