using AyCode.Core.Serializers.Attributes;
using AyCode.Core.Serializers.Toons;
using FruitBank.Common.Dtos;
using LinqToDB;
using LinqToDB.Mapping;
using Mango.Nop.Core.Entities;
using Newtonsoft.Json;
using System.ComponentModel.DataAnnotations.Schema;
using Column = LinqToDB.Mapping.ColumnAttribute;
using Table = LinqToDB.Mapping.TableAttribute;

namespace FruitBank.Common.Entities;

[AcBinarySerializable(false, true, false, true, false, false)]
[ToonDescription("Line item for product reconciliation", Purpose = "Reconciles snapshot quantity with physical count to calculate final stock delta")]
[Table(Name = FruitBankConstClient.StockTakingItemDbTableName)]
[System.ComponentModel.DataAnnotations.Schema.Table(FruitBankConstClient.StockTakingItemDbTableName)]
public sealed class StockTakingItem : MgStockTakingItem<StockTaking, ProductDto>
{
    public bool IsMeasurable { get; set; }

    [Column(DataType = DataType.DecFloat, CanBeNull = false)]
    public double OriginalNetWeight { get; set; }

    [Column(DataType = DataType.DecFloat, CanBeNull = false)]
    public double MeasuredNetWeight { get; set; }

    [ToonDescription(Purpose = "Reserved stock buffer (not yet shipped) to prevent double-deduction during closing")]
    public int InProcessOrdersQuantity { get; set; }

    [NotColumn, NotMapped, JsonIgnore, System.Text.Json.Serialization.JsonIgnore]
    [ToonDescription(BusinessRule = "get => OriginalStockQuantity + InProcessOrdersQuantity", Purpose = "Snapshot of total logical stock at session start")]
    public int TotalOriginalQuantity => OriginalStockQuantity + InProcessOrdersQuantity;

    [NotColumn, NotMapped, JsonIgnore, System.Text.Json.Serialization.JsonIgnore]
    [ToonDescription(Purpose = "Final adjustment value for Product.StockQuantity", BusinessRule = "get => IsMeasured ? MeasuredStockQuantity - TotalOriginalQuantity : 0")]
    public int QuantityDiff => IsMeasured ? MeasuredStockQuantity - TotalOriginalQuantity : 0;

    [NotColumn, NotMapped, JsonIgnore, System.Text.Json.Serialization.JsonIgnore]
    [ToonDescription(BusinessRule = "get => IsMeasurable && IsMeasured ? double.Round(MeasuredNetWeight - OriginalNetWeight, 1) : 0d")]
    public double NetWeightDiff => IsMeasurable && IsMeasured ? double.Round(MeasuredNetWeight - OriginalNetWeight, 1) : 0d;

    [Association(ThisKey = nameof(Id), OtherKey = nameof(StockTakingItemPallet.StockTakingItemId), CanBeNull = true)]
    public List<StockTakingItemPallet>? StockTakingItemPallets { get; set; }

    [NotColumn, NotMapped, JsonIgnore, System.Text.Json.Serialization.JsonIgnore]
    [ToonDescription(Purpose = "Status flag", BusinessRule = "get => !IsInvalid && (TotalOriginalQuantity != 0 || OriginalNetWeight != 0)")]
    public bool IsRequiredForMeasuring => !IsInvalid && (TotalOriginalQuantity != 0 || OriginalNetWeight != 0);

    [NotColumn, NotMapped, JsonIgnore, System.Text.Json.Serialization.JsonIgnore]
    [ToonDescription(Purpose = "Status flag", BusinessRule = "get => TotalOriginalQuantity < 0")]
    public bool IsInvalid => TotalOriginalQuantity < 0;

    [NotColumn, NotMapped, JsonIgnore, System.Text.Json.Serialization.JsonIgnore]
    [ToonDescription(BusinessRule = "get => conditional string based on IsInvalid, IsMeasured, IsRequiredForMeasuring")]
    public string DisplayText
    {
        get
        {
            if (IsInvalid) return $"[HIBA] {Product!.Name}";
            if (IsMeasured) return $"[KÉSZ] {Product!.Name}";

            return IsRequiredForMeasuring ? $"[KÖT] {Product!.Name}" : $"{Product!.Name}";
        }
    }
}