using System.ComponentModel.DataAnnotations;
using ERPCore.Domain.Enums;

namespace ERPCore.Dtos.Items;

// Response DTOs (docs/11-BACKEND-PHASE1.md §2.1) --------------------------------

/// <summary>Row shape for <c>GET /items</c>.</summary>
public sealed record ItemListItemDto(
    int ItemId, string Sku, string Name, int CategoryId, int? SubCategoryId, int? BrandId,
    int BaseUomId, int? DefaultVendorId, StockNature StockNature, TrackingMode TrackingMode,
    Warranty Warranty, int? WarrantyPeriodMonths,
    string? TaxClass, decimal? SalePrice,
    decimal? ContentQty, MeasureUnit? ContentUnit,
    decimal? ContentBaseQty, MeasureUnit? ContentBaseUnit,
    EntityStatus Status);

/// <summary>A single per-warehouse reorder policy row.</summary>
public sealed record ItemReorderDto(int WarehouseId, decimal ReorderPoint, decimal ReorderQty);

/// <summary>
/// Full item resource for <c>GET /items/{id}</c> and create/update responses.
/// <para>
/// <c>ContentBaseQty</c>/<c>ContentBaseUnit</c> are echoed back so a detail screen can show
/// what the entered size normalised to (1.5 L ⇒ 1500 ml) — they are server-derived and are
/// not accepted on write.
/// </para>
/// </summary>
public sealed record ItemDetailDto(
    int ItemId, string Sku, string Name, string? Description, int CategoryId,
    int? SubCategoryId, int? BrandId, int BaseUomId, int? DefaultVendorId,
    StockNature StockNature, TrackingMode TrackingMode,
    Warranty Warranty, int? WarrantyPeriodMonths,
    string? TaxClass, decimal? SalePrice,
    decimal? ContentQty, MeasureUnit? ContentUnit,
    decimal? ContentBaseQty, MeasureUnit? ContentBaseUnit,
    EntityStatus Status, IReadOnlyList<ItemReorderDto> Reorder,
    DateTime CreatedAt, DateTime? UpdatedAt);

/// <summary>Response body for <c>PUT /items/{id}/reorder</c>.</summary>
public sealed record ItemReorderSettingsDto(IReadOnlyList<ItemReorderDto> Settings);

// Request DTOs — narrow: server-controlled fields (status, ids, timestamps)
// are intentionally excluded to prevent over-posting (02-SECURITY B.6 / C.1). ----

// Note: the SKU is generated client-side (it encodes the chosen item-type values, e.g.
// "BL-100-0003"); the server only enforces uniqueness. There is no item-type field here
// by design — items carry no item-type reference (docs/10 Part C.9).

public sealed class CreateItemRequest
{
    [Required, StringLength(50)] public string Sku { get; set; } = string.Empty;
    [Required, StringLength(200)] public string Name { get; set; } = string.Empty;
    [StringLength(1000)] public string? Description { get; set; }
    [Required] public int CategoryId { get; set; }
    /// <summary>Optional; must belong to <see cref="CategoryId"/>. Rejected when subcategories are disabled.</summary>
    public int? SubCategoryId { get; set; }
    /// <summary>Optional. Rejected when brands are disabled.</summary>
    public int? BrandId { get; set; }
    [Required] public int BaseUomId { get; set; }
    public int? DefaultVendorId { get; set; }
    [Required, EnumDataType(typeof(StockNature))] public StockNature StockNature { get; set; }
    [EnumDataType(typeof(TrackingMode))] public TrackingMode TrackingMode { get; set; } = TrackingMode.None;
    [EnumDataType(typeof(Warranty))] public Warranty Warranty { get; set; } = Warranty.NonWarranty;
    /// <summary>Required (one of <see cref="Enums.WarrantyPeriods.AllowedMonths"/>) when <see cref="Warranty"/> is Warranty; ignored otherwise.</summary>
    public int? WarrantyPeriodMonths { get; set; }
    [StringLength(20)] public string? TaxClass { get; set; }
    /// <summary>Optional fixed sale price (Sales only). Null ⇒ sell at stock/FIFO value.</summary>
    [Range(0, double.MaxValue)] public decimal? SalePrice { get; set; }

    /// <summary>
    /// How much one pack holds. Supply with <see cref="ContentUnit"/> or leave both null
    /// for items with no measurable content. The normalised base pair is derived by the
    /// server and is deliberately not accepted here.
    /// </summary>
    [Range(0.0001, double.MaxValue)] public decimal? ContentQty { get; set; }
    [EnumDataType(typeof(MeasureUnit))] public MeasureUnit? ContentUnit { get; set; }
}

public sealed class UpdateItemRequest
{
    [Required, StringLength(50)] public string Sku { get; set; } = string.Empty;
    [Required, StringLength(200)] public string Name { get; set; } = string.Empty;
    [StringLength(1000)] public string? Description { get; set; }
    [Required] public int CategoryId { get; set; }
    /// <summary>Optional; must belong to <see cref="CategoryId"/>. Rejected when subcategories are disabled.</summary>
    public int? SubCategoryId { get; set; }
    /// <summary>Optional. Rejected when brands are disabled.</summary>
    public int? BrandId { get; set; }
    [Required] public int BaseUomId { get; set; }
    public int? DefaultVendorId { get; set; }
    [Required, EnumDataType(typeof(StockNature))] public StockNature StockNature { get; set; }
    [EnumDataType(typeof(TrackingMode))] public TrackingMode TrackingMode { get; set; } = TrackingMode.None;
    [EnumDataType(typeof(Warranty))] public Warranty Warranty { get; set; } = Warranty.NonWarranty;
    /// <summary>Required (one of <see cref="Enums.WarrantyPeriods.AllowedMonths"/>) when <see cref="Warranty"/> is Warranty; ignored otherwise.</summary>
    public int? WarrantyPeriodMonths { get; set; }
    [StringLength(20)] public string? TaxClass { get; set; }
    /// <summary>Optional fixed sale price (Sales only). Null ⇒ sell at stock/FIFO value.</summary>
    [Range(0, double.MaxValue)] public decimal? SalePrice { get; set; }

    /// <summary>
    /// How much one pack holds. Supply with <see cref="ContentUnit"/> or leave both null
    /// for items with no measurable content. The normalised base pair is derived by the
    /// server and is deliberately not accepted here.
    /// </summary>
    [Range(0.0001, double.MaxValue)] public decimal? ContentQty { get; set; }
    [EnumDataType(typeof(MeasureUnit))] public MeasureUnit? ContentUnit { get; set; }
}

public sealed class UpdateItemStatusRequest
{
    [Required, EnumDataType(typeof(EntityStatus))] public EntityStatus Status { get; set; }
}

public sealed class ReorderSettingInput
{
    [Required] public int WarehouseId { get; set; }
    [Range(0, double.MaxValue)] public decimal ReorderPoint { get; set; }
    [Range(0, double.MaxValue)] public decimal ReorderQty { get; set; }
}

public sealed class UpdateReorderRequest
{
    [Required, MinLength(1)] public List<ReorderSettingInput> Settings { get; set; } = new();
}
