using System.ComponentModel.DataAnnotations;

namespace Extrudex.API.DTOs.Spools;

/// <summary>
/// Response DTO for Spool entity — the core inventory unit of Extrudex.
/// Contains all spool details including denormalized material names for display.
/// </summary>
public class SpoolResponse
{
    /// <summary>Unique identifier for the spool.</summary>
    public Guid Id { get; set; }

    /// <summary>Foreign key to the base material.</summary>
    public Guid MaterialBaseId { get; set; }

    /// <summary>Name of the base material (e.g., "PLA", "PETG").</summary>
    public string MaterialBaseName { get; set; } = string.Empty;

    /// <summary>Foreign key to the material finish.</summary>
    public Guid MaterialFinishId { get; set; }

    /// <summary>Name of the material finish (e.g., "Basic", "Matte").</summary>
    public string MaterialFinishName { get; set; } = string.Empty;

    /// <summary>Foreign key to the optional material modifier. Null if none.</summary>
    public Guid? MaterialModifierId { get; set; }

    /// <summary>Name of the material modifier (e.g., "Carbon Fiber"). Null if none.</summary>
    public string? MaterialModifierName { get; set; }

    /// <summary>Brand name (e.g., "Bambu Lab", "Polymaker").</summary>
    public string Brand { get; set; } = string.Empty;

    /// <summary>Human-readable color name (e.g., "Fire Engine Red").</summary>
    public string ColorName { get; set; } = string.Empty;

    /// <summary>Hex color code (e.g., "#FF0000").</summary>
    public string ColorHex { get; set; } = string.Empty;

    /// <summary>Total spool weight in grams when full.</summary>
    public decimal WeightTotalGrams { get; set; }

    /// <summary>Current remaining weight in grams.</summary>
    public decimal WeightRemainingGrams { get; set; }

    /// <summary>Filament diameter in millimeters. Typically 1.75mm.</summary>
    public decimal FilamentDiameterMm { get; set; }

    /// <summary>Manufacturer-assigned serial number. Must be unique.</summary>
    public string SpoolSerial { get; set; } = string.Empty;

    /// <summary>Purchase price per spool. Null if not tracked.</summary>
    public decimal? PurchasePrice { get; set; }

    /// <summary>Date the spool was purchased or received.</summary>
    public DateTime? PurchaseDate { get; set; }

    /// <summary>Whether the spool is currently active and available.</summary>
    public bool IsActive { get; set; }

    /// <summary>Timestamp when this record was created (UTC).</summary>
    public DateTime CreatedAt { get; set; }

    /// <summary>Timestamp when this record was last updated (UTC).</summary>
    public DateTime UpdatedAt { get; set; }
}

/// <summary>
/// Request DTO for creating a new spool.
/// All required fields must be provided. MaterialFinish is required — use "Basic" as the default.
/// </summary>
public class CreateSpoolRequest
{
    /// <summary>Foreign key to the base material. Required.</summary>
    [Required(ErrorMessage = "MaterialBaseId is required.")]
    public Guid MaterialBaseId { get; set; }

    /// <summary>Foreign key to the material finish. Required — default is "Basic".</summary>
    [Required(ErrorMessage = "MaterialFinishId is required.")]
    public Guid MaterialFinishId { get; set; }

    /// <summary>Foreign key to the optional material modifier. Null if none applies.</summary>
    public Guid? MaterialModifierId { get; set; }

    /// <summary>Brand name (e.g., "Bambu Lab", "Polymaker"). Required, max 200 characters.</summary>
    [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;

    /// <summary>Human-readable color name (e.g., "Fire Engine Red"). Required, max 200 characters.</summary>
    [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;

    /// <summary>Hex color code (e.g., "#FF0000"). Required, must be valid 7-char hex.</summary>
    [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;

    /// <summary>Total spool weight in grams when full. Must be greater than zero.</summary>
    [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; }

    /// <summary>Current remaining weight in grams. Must be non-negative.</summary>
    [Required(ErrorMessage = "WeightRemainingGrams is required.")]
    [Range(0, 100000, ErrorMessage = "Remaining weight must be between 0 and 100,000 grams.")]
    public decimal WeightRemainingGrams { get; set; }

    /// <summary>Filament diameter in mm. Defaults to 1.75. Must be greater than zero.</summary>
    [Range(0.1, 10.0, ErrorMessage = "Filament diameter must be between 0.1 and 10.0 mm.")]
    public decimal FilamentDiameterMm { get; set; } = 1.75m;

    /// <summary>Manufacturer-assigned serial number. Must be unique, max 200 characters.</summary>
    [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;

    /// <summary>Optional purchase price per spool. Must be non-negative if provided.</summary>
    [Range(0, 1000000, ErrorMessage = "Purchase price must be between 0 and 1,000,000.")]
    public decimal? PurchasePrice { get; set; }

    /// <summary>Optional purchase date. Must be a valid date if provided.</summary>
    public DateTime? PurchaseDate { get; set; }

    /// <summary>Whether the spool is active. Defaults to true.</summary>
    public bool IsActive { get; set; } = true;
}

/// <summary>
/// Request DTO for updating an existing spool.
/// All required fields must be provided for a full update.
/// </summary>
public class UpdateSpoolRequest
{
    /// <summary>Foreign key to the base material. Required.</summary>
    [Required(ErrorMessage = "MaterialBaseId is required.")]
    public Guid MaterialBaseId { get; set; }

    /// <summary>Foreign key to the material finish. Required.</summary>
    [Required(ErrorMessage = "MaterialFinishId is required.")]
    public Guid MaterialFinishId { get; set; }

    /// <summary>Foreign key to the optional material modifier. Null if none applies.</summary>
    public Guid? MaterialModifierId { get; set; }

    /// <summary>Brand name. Required, max 200 characters.</summary>
    [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;

    /// <summary>Human-readable color name. Required, max 200 characters.</summary>
    [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;

    /// <summary>Hex color code (e.g., "#FF0000"). Required, must be valid 7-char hex.</summary>
    [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;

    /// <summary>Total spool weight in grams when full. Must be greater than zero.</summary>
    [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; }

    /// <summary>Current remaining weight in grams. Must be non-negative.</summary>
    [Required(ErrorMessage = "WeightRemainingGrams is required.")]
    [Range(0, 100000, ErrorMessage = "Remaining weight must be between 0 and 100,000 grams.")]
    public decimal WeightRemainingGrams { get; set; }

    /// <summary>Filament diameter in mm. Must be greater than zero.</summary>
    [Range(0.1, 10.0, ErrorMessage = "Filament diameter must be between 0.1 and 10.0 mm.")]
    public decimal FilamentDiameterMm { get; set; } = 1.75m;

    /// <summary>Manufacturer-assigned serial number. Must be unique, max 200 characters.</summary>
    [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;

    /// <summary>Optional purchase price per spool. Must be non-negative if provided.</summary>
    [Range(0, 1000000, ErrorMessage = "Purchase price must be between 0 and 1,000,000.")]
    public decimal? PurchasePrice { get; set; }

    /// <summary>Optional purchase date.</summary>
    public DateTime? PurchaseDate { get; set; }

    /// <summary>Whether the spool is active.</summary>
    public bool IsActive { get; set; } = true;
}