using AyCode.Core.Serializers.Attributes;
using AyCode.Core.Serializers.Toons;
using FruitBank.Common.Interfaces;
using LinqToDB.Mapping;
using Mango.Nop.Core.Dtos;
using Mango.Nop.Core.Extensions;
using Mango.Nop.Core.Interfaces.ForeignKeys;
using Newtonsoft.Json;
using Nop.Core.Domain.Catalog;

//using Nop.Core.Domain.Catalog;
using Nop.Core.Domain.Common;
using Nop.Core.Domain.Orders;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq.Expressions;

namespace FruitBank.Common.Dtos;

[AcBinarySerializable(false, true, false, true, false, false)]
[LinqToDB.Mapping.Table(Name = nameof(Product))]
[System.ComponentModel.DataAnnotations.Schema.Table(nameof(Product))]
[ToonDescription("Product data with measurements and generic attributes", TypeRelation = ToonTypeRelation.DtoOf, RelatedTypes = [typeof(Product)])]
public class ProductDto : MgProductDto, IProductDto
{
    [NotColumn, NotMapped, JsonIgnore, System.Text.Json.Serialization.JsonIgnore]
    private static Expression<Func<ProductDto, GenericAttributeDto, bool>> RelationWithGenericAttribute => (orderItemDto, genericAttributeDto) =>
        orderItemDto.Id == genericAttributeDto.EntityId && genericAttributeDto.KeyGroup == nameof(Product);// nameof(Product);


    [Association(ThisKey = nameof(Id), OtherKey = nameof(GenericAttributeDto.EntityId), ExpressionPredicate = nameof(RelationWithGenericAttribute), CanBeNull = false)]
    public List<GenericAttributeDto> GenericAttributes { get; set; }

    /// <summary>
    /// A nopCommerce <c>Product.Gtin</c> oszlopa. <b>Átmenetileg az EKÁER VTSZ-t (vámtarifaszámot) tárolja</b> —
    /// a jövőbeli <c>ShippingToEkaerMapper</c> innen olvassa a <c>tradeCardItem.productVtsz</c> értékét.
    /// ⚠️ A GTIN ≠ VTSZ (a GTIN globális kereskedelmi cikkszám, a VTSZ vámtarifaszám). Külön mezőbe választandó —
    /// lásd <c>FruitBank.Common/docs/DATAMODEL/DATAMODEL_ISSUES.md#fbankapp-dmodel-i-p6x4</c>.
    /// </summary>
    [LinqToDB.Mapping.Column(nameof(Product.Gtin))]
    [ToonDescription(Purpose = "nopCommerce Gtin column — holds the EKÁER VTSZ (customs tariff number) used as the trade-card item productVtsz in NAV road-freight reporting.")]
    public string? Gtin { get; set; }

    public ProductDto() :base()
    { }
    public ProductDto(int productId) : base(productId)
    { }
    //public ProductDto(Product product) : base(product)
    //{ }

    [NotColumn, NotMapped, JsonIgnore, System.Text.Json.Serialization.JsonIgnore]
    [ToonDescription(Purpose = "Master flag: if false, the system bypasses weight validation but still creates one Measurement Record (PalletItem) with TrayQuantity.", BusinessRule = "get => GenericAttributes.GetValueOrDefault<bool>('IsMeasurable')")]
    public bool IsMeasurable
    {
        get => GenericAttributes.GetValueOrDefault<bool>(nameof(IMeasurable.IsMeasurable));
        set
        {
            throw new Exception($"ProductDto.IsMeasurable not set");

            //Direkt legyen exception! - J.
            var ga = GenericAttributes.SingleOrDefault(x => x.Key == nameof(IMeasurable.IsMeasurable))!;
            ga.Value = value.ToString();
        }
    }

    [NotColumn, NotMapped, JsonIgnore, System.Text.Json.Serialization.JsonIgnore]
    [ToonDescription(BusinessRule = "get => GenericAttributes.GetValueOrDefault<double>('Tare')")]
    public double Tare
    {
        get => GenericAttributes.GetValueOrDefault<double>(nameof(ITare.Tare));
        //get => CommonHelper.To<double>(GenericAttributes.SingleOrDefault(x => x.Key == nameof(ITare.Tare))?.Value ?? "0");
        set => throw new Exception($"ProductDto.Tare not set");
    }

    [NotColumn, NotMapped, JsonIgnore, System.Text.Json.Serialization.JsonIgnore]
    [ToonDescription(BusinessRule = "get => GenericAttributes.GetValueOrDefault<double>('NetWeight')")]
    public double NetWeight
    {
        get => GenericAttributes.GetValueOrDefault<double>(nameof(IMeasuringNetWeight.NetWeight));
        set => throw new Exception($"ProductDto.NetWeight not set");
    }

    [NotColumn, NotMapped, JsonIgnore, System.Text.Json.Serialization.JsonIgnore]
    [ToonDescription(BusinessRule = "get => GenericAttributes.GetValueOrDefault<int>('IncomingQuantity')")]
    public int IncomingQuantity
    {
        get => GenericAttributes.GetValueOrDefault<int>(nameof(IIncomingQuantity.IncomingQuantity));
        set => throw new Exception($"ProductDto.IncomingQuantity not set");
        //set
        //{
        //    var ga = GenericAttributes.FirstOrDefault(ga => ga.Key == nameof(IIncomingQuantity.IncomingQuantity)) ??
        //             GenericAttributes.AddNewGenericAttribute(nameof(Product), nameof(IIncomingQuantity.IncomingQuantity), value.ToString(), Id);

        //    ga.Value = value.ToString();
        //}
    }

    [NotColumn, NotMapped, JsonIgnore, System.Text.Json.Serialization.JsonIgnore]
    [ToonDescription(BusinessRule = "get => StockQuantity + IncomingQuantity")]
    public int AvailableQuantity => StockQuantity + IncomingQuantity;

    [NotColumn, NotMapped, JsonIgnore, System.Text.Json.Serialization.JsonIgnore]
    [ToonDescription(BusinessRule = "get => GenericAttributes.GetValueOrDefault<double>('AverageWeight')")]
    public double AverageWeight => GenericAttributes.GetValueOrDefault<double>(nameof(IProductDto.AverageWeight));

    [NotColumn, NotMapped, JsonIgnore, System.Text.Json.Serialization.JsonIgnore]
    [ToonDescription(BusinessRule = "get => GenericAttributes.GetValueOrDefault<double>('AverageWeightTreshold')")]
    public double AverageWeightTreshold => GenericAttributes.GetValueOrDefault<double>(nameof(IProductDto.AverageWeightTreshold));

    public bool HasMeasuringValues() => Id > 0 && NetWeight != 0 && IsMeasurable;
}