using AyCode.Core.Interfaces;
using AyCode.Core.Serializers.Attributes;
using AyCode.Core.Serializers.Toons;
using FruitBank.Common.Dtos;
using FruitBank.Common.Enums;
using FruitBank.Common.Interfaces;
using LinqToDB;
using LinqToDB.Mapping;
using Mango.Nop.Core.Entities;
using Newtonsoft.Json;
using Nop.Core.Domain.Customers;
using Nop.Core.Domain.Orders;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Column = LinqToDB.Mapping.ColumnAttribute;
//using Nop.Core.Domain.Catalog;
using DataType = LinqToDB.DataType;
using Table = LinqToDB.Mapping.TableAttribute;

namespace FruitBank.Common.Entities;

[AcBinarySerializable(false, true, false, true, false, false)]
[ToonDescription("Shipping document item with measurements and pallets", Purpose = "Represents a specific product line item within a shipping document, storing the discrepancy between the supplier's declared weight/quantity and the warehouse's measured values")]
[Table(Name = FruitBankConstClient.ShippingItemDbTableName)]
[System.ComponentModel.DataAnnotations.Schema.Table(FruitBankConstClient.ShippingItemDbTableName)]
public class ShippingItem : MgEntityBase, IShippingItem
{
    public int ShippingDocumentId { get; set; }
    public int? PalletId { get; set; }
    public int? ProductId { get; set; }
    
    public string Name { get; set; }
    public string NameOnDocument { get; set; }
    public string HungarianName { get; set; }

    [NotColumn, NotMapped, JsonIgnore, System.Text.Json.Serialization.JsonIgnore]
    [ToonDescription(BusinessRule = "get => ProductDto?.Name ?? Name")]
    public string ProductName => ProductDto?.Name ?? Name;
    
    public int PalletsOnDocument { get; set; }

    public int QuantityOnDocument { get; set; }

    [Column(DataType = DataType.DecFloat)] public double NetWeightOnDocument { get; set; }
    [Column(DataType = DataType.DecFloat)] public double GrossWeightOnDocument { get; set; }
    [Column(DataType = DataType.DecFloat)] public double UnitPriceOnDocument { get; set; }

    /// <summary>
    /// Általában megegyezik a PalletsOnDocument-el, de minimum 1! Ha nincs raklap, akkor is 1! Néha előfordulhat, hogy kevesebb raklap érkezik és olyankor kell tudni módosítani a mérések számát.
    /// </summary>
    [Range(1, 100000, ErrorMessage = "The MeasuringCount value should be a number between 1 and 100,000.")]
    public int MeasuringCount { get; set; } = 1;

    //[Nullable]
    //[Column(CanBeNull = true)]
    [Range(1, 100000, ErrorMessage = "The MeasuredQuantity value should be a number between 1 and 100,000.")]
    public int MeasuredQuantity { get; set; }

    //[Nullable]
    [Column(DataType = DataType.DecFloat, CanBeNull = false)]
    [Range(1, 100000, ErrorMessage = "The MeasuredNetWeight value should be a number between 1 and 100,000.")]
    public double MeasuredNetWeight { get; set; }

    //[Nullable]
    //Precision = 1
    [Column(DataType = DataType.DecFloat, CanBeNull = false)]
    [Range(1, 100000, ErrorMessage = "The MeasuredGrossWeight value should be a number between 1 and 100,000.")]
    public double MeasuredGrossWeight { get; set; }

    public bool IsMeasurable { get; set; }
    public bool IsMeasured { get; set; }

    [LinqToDB.Mapping.Association(ThisKey = nameof(PalletId), OtherKey = nameof(Pallet.Id), CanBeNull = true)]
    public Pallet? Pallet { get; set; }

    [LinqToDB.Mapping.Association(ThisKey = nameof(ProductId), OtherKey = nameof(ProductDto.Id), CanBeNull = true)]
    public ProductDto? ProductDto { get; set; }

    [LinqToDB.Mapping.Association(ThisKey = nameof(ShippingDocumentId), OtherKey = nameof(ShippingDocument.Id), CanBeNull = true)]
    public ShippingDocument? ShippingDocument { get; set; }

    [LinqToDB.Mapping.Association(ThisKey = nameof(Id), OtherKey = nameof(ShippingItemPallet.ShippingItemId), CanBeNull = true)]
    public List<ShippingItemPallet>? ShippingItemPallets { get; set; }

    [SkipValuesOnUpdate] public DateTime Created { get; set; }
    public DateTime Modified { get; set; }

    [NotColumn, NotMapped, JsonIgnore, System.Text.Json.Serialization.JsonIgnore]
    [ToonDescription(BusinessRule = "get => complex conditional logic based on IsMeasured and ShippingItemPallets status")]
    public MeasuringStatus MeasuringStatus
    {
        get
        {
            if (IsMeasured) return MeasuringStatus.Finnished;

            return ShippingItemPallets?.Any(oip => oip.MeasuringStatus == MeasuringStatus.Started) ?? false ? MeasuringStatus.Started : MeasuringStatus.NotStarted;
        }
    }

    public bool IsValidMeasuringValues()
    {
        return /*ProductId > 0 && */MeasuringCount > 0 && MeasuredQuantity > 0 && (!IsMeasurable || (MeasuredNetWeight > 0 && MeasuredGrossWeight > 0));
    }
}