using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Lagerbestand.Models;
///
/// Status of a tire stack in the storage system
///
public enum TireStackStatus
{
///
/// Tires are currently stored in the warehouse
///
Stored = 0,
///
/// Tires have been picked up by the customer
///
PickedUp = 1,
///
/// Tires have been disposed/recycled
///
Disposed = 2,
///
/// Tires are reserved for pickup
///
Reserved = 3,
///
/// Tires are in inventory (shop stock, not customer-owned)
///
Inventory = 4,
///
/// Tires are currently mounted on the customer's vehicle (after a seasonal swap).
/// They can be re-stored later when swapping back.
///
OnVehicle = 5
}
///
/// Represents a stack of exactly 4 tires as a single indivisible unit.
/// A stack is always 4 identical tires - there is no variable count.
/// This is the main entity that tracks customer tire storage and shop inventory.
///
public class TireStack
{
///
/// Number of tires in a stack - always 4
///
public const int TiresPerStack = 4;
[Key]
public Guid Id { get; set; } = Guid.NewGuid();
///
/// Custom item count for inventory (default: 4 = standard stack).
/// Only used for inventory items. Customer stacks always use TiresPerStack.
///
[Range(1, 99)]
public int ItemCount { get; set; } = TiresPerStack;
///
/// Unique identifier/ticket number for this tire stack (e.g., "TS-2024-0001")
/// This serves as the primary human-readable identifier.
///
[Required]
[MaxLength(50)]
public string TicketNumber { get; set; } = string.Empty;
///
/// Customer who owns these tires (null for shop inventory)
///
public Guid? CustomerId { get; set; }
[ForeignKey(nameof(CustomerId))]
public Customer? Customer { get; set; }
///
/// Vehicle these tires belong to (null for shop inventory or legacy data)
///
public Guid? VehicleId { get; set; }
[ForeignKey(nameof(VehicleId))]
public Vehicle? Vehicle { get; set; }
///
/// Current storage location (null if picked up)
///
public Guid? StorageLocationId { get; set; }
[ForeignKey(nameof(StorageLocationId))]
public StorageLocation? StorageLocation { get; set; }
///
/// Tire category/type (used for inventory categorization)
///
public Guid? CatalogItemId { get; set; }
[ForeignKey(nameof(CatalogItemId))]
public CatalogItem? CatalogItem { get; set; }
///
/// Tread depth / condition measurements (e.g. imported from QR report)
///
public ICollection Inspections { get; set; } = new List();
///
/// Current status of the tire stack
///
public TireStackStatus Status { get; set; } = TireStackStatus.Stored;
///
/// Tire size (e.g., "225/45R17")
///
[MaxLength(50)]
public string? TireSize { get; set; }
///
/// Tire brand (e.g., "Michelin", "Continental")
///
[MaxLength(100)]
public string? TireBrand { get; set; }
///
/// Tire model (e.g., "Pilot Sport 4", "WinterContact TS 860")
///
[MaxLength(100)]
public string? TireModel { get; set; }
///
/// Season type
///
public TireSeason Season { get; set; } = TireSeason.Sommer;
///
/// Tread depth in mm (average of all 4 tires)
///
[Range(0, 10)]
public decimal? TreadDepth { get; set; }
///
/// DOT/manufacturing date code (e.g., "2523" = week 25 of 2023)
///
[MaxLength(20)]
public string? DotCode { get; set; }
///
/// Whether tires are mounted on rims
///
public bool WithRims { get; set; } = true;
///
/// Rim size if with rims (e.g., "17 Zoll")
///
[MaxLength(20)]
public string? RimSize { get; set; }
///
/// TPMS sensors present
///
public bool HasTpms { get; set; }
///
/// Tire condition rating
///
public TireCondition Condition { get; set; } = TireCondition.Good;
///
/// Additional notes about the tire condition or special requirements
///
[MaxLength(1000)]
public string? Notes { get; set; }
///
/// Date when tires were stored
///
public DateTime StoredAt { get; set; } = DateTime.UtcNow;
///
/// Date when tires were picked up
///
public DateTime? PickedUpAt { get; set; }
///
/// Expected pickup date (next season change)
///
public DateTime? ExpectedPickupDate { get; set; }
///
/// User who stored the tires
///
public Guid? StoredByUserId { get; set; }
///
/// User who processed the pickup
///
public Guid? PickedUpByUserId { get; set; }
public bool IsActive { get; set; } = true;
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
public DateTime? UpdatedAt { get; set; }
///
/// Whether this is shop inventory (not customer-owned)
///
[NotMapped]
public bool IsInventory => CustomerId == null;
///
/// Display name - customer name or category name for inventory
///
[NotMapped]
public string DisplayName => Customer?.FullName ?? CatalogItem?.Name ?? "Lagerbestand";
///
/// Summary description for display
///
[NotMapped]
public string Summary
{
get
{
var parts = new List();
if (!string.IsNullOrEmpty(TireBrand)) parts.Add(TireBrand);
if (!string.IsNullOrEmpty(TireSize)) parts.Add(TireSize);
parts.Add(Season.ToString());
if (WithRims) parts.Add("mit Felgen");
return string.Join(" | ", parts);
}
}
///
/// Status display text in German
///
[NotMapped]
public string StatusText => Status switch
{
TireStackStatus.Stored => "Eingelagert",
TireStackStatus.PickedUp => "Abgeholt",
TireStackStatus.Disposed => "Entsorgt",
TireStackStatus.Reserved => "Reserviert",
TireStackStatus.Inventory => "Lagerbestand",
TireStackStatus.OnVehicle => "Montiert",
_ => "Unbekannt"
};
///
/// Days stored (for billing purposes)
///
[NotMapped]
public int DaysStored => (PickedUpAt ?? DateTime.UtcNow).Subtract(StoredAt).Days;
///
/// Condition display text in German
///
[NotMapped]
public string ConditionText => Condition switch
{
TireCondition.Excellent => "Sehr gut",
TireCondition.Good => "Gut",
TireCondition.Fair => "Ausreichend",
TireCondition.Poor => "Mangelhaft",
TireCondition.Critical => "Kritisch",
_ => "Unbekannt"
};
}