using AyCode.Services.Nav.Ekaer;
using AyCode.Services.Nav.Ekaer.Models;
using FruitBank.Common.Dtos;
using FruitBank.Common.Entities;
using FruitBank.Common.Services.Ekaer;
using TradeReasonType = AyCode.Services.Nav.Ekaer.Models.Common.TradeReasonType;
using TradeType = AyCode.Services.Nav.Ekaer.Models.Common.TradeType;

namespace FruitBankHybrid.Shared.Tests.Ekaer;

/// <summary>
/// Unit tesztek a <see cref="ShippingToEkaerMapper"/>-re — a FruitBank <c>Shipping</c> → NAV EKÁER tradeCard
/// leképezésre. Tisztán memóriában felépített entitásokon fut (nincs hálózat/DB), determinisztikus.
/// </summary>
[TestClass]
public sealed class ShippingToEkaerMapperTests
{
    private static readonly ShippingToEkaerMapper Mapper = new();

    // ---- Helpers ------------------------------------------------------------

    private static Shipping CreateShipping(string sellerCountry = "HU", string plate = "ABC-123", bool withTrailer = true)
    {
        var item = new ShippingItem
        {
            Id = 1,
            Name = "Alma",
            ProductDto = new ProductDto { Gtin = "08081010", Name = "Alma" },
            MeasuredGrossWeight = 123.5,
            MeasuredQuantity = 10,
            UnitPriceOnDocument = 5.0,
        };

        var document = new ShippingDocument
        {
            Country = sellerCountry,
            Partner = new Partner
            {
                Name = "Beszállító Kft",
                TaxId = "12345678-2-42",
                CountryCode = sellerCountry,
                PostalCode = "1011",
                City = "Budapest",
                Street = "Fő utca 1",
            },
            ShippingItems = [item],
        };

        var shipping = new Shipping
        {
            CargoPartner = new CargoPartner { Name = "Fuvaros Zrt", CountryCode = "HU" },
            CargoTruck = new CargoTruck { LicencePlate = plate, CountryCode = "HU", IsTrailer = false },
            ShippingDocuments = [document],
        };

        if (withTrailer)
            shipping.CargoTrailer = new CargoTruck { LicencePlate = "XYZ-789", CountryCode = "HU", IsTrailer = true };

        return shipping;
    }

    private static EkaerCompanyInfo CreateCompany() => new()
    {
        Name = "FruitBank Kft",
        TaxId = "98765432-2-41",
        CountryCode = "HU",
        PostalCode = "1102",
        City = "Budapest",
        Street = "Raktar utca 5",
        UnloadLocation = new LocationType
        {
            Name = "FruitBank Raktár",
            VatNumber = "98765432-2-41",
            Country = "HU",
            ZipCode = "1102",
            City = "Budapest",
            Street = "Raktar utca",
            StreetNumber = "5",
        },
    };

    // ---- Granularitás / index ----------------------------------------------

    [TestMethod]
    public void MapShipping_ProducesOneOperationPerDocument_WithSequentialIndex()
    {
        var shipping = CreateShipping();
        shipping.ShippingDocuments!.Add(new ShippingDocument
        {
            Country = "HU",
            Partner = new Partner { Name = "Másik Beszállító", CountryCode = "HU" },
            ShippingItems = [],
        });

        var ops = Mapper.MapShipping(shipping, CreateCompany());

        Assert.AreEqual(2, ops.Count, "dokumentumonként egy tradeCard");
        Assert.AreEqual(1, ops[0].Index);
        Assert.AreEqual(2, ops[1].Index);
        Assert.AreEqual(OperationType.Create, ops[0].Operation, "alapértelmezett művelet: Create");
    }

    [TestMethod]
    public void MapShipping_NullDocuments_ReturnsEmpty()
    {
        var ops = Mapper.MapShipping(new Shipping { ShippingDocuments = null }, CreateCompany());
        Assert.AreEqual(0, ops.Count);
    }

    [TestMethod]
    public void MapShipping_HonorsExplicitOperation()
    {
        var ops = Mapper.MapShipping(CreateShipping(), CreateCompany(), OperationType.Modify);
        Assert.AreEqual(OperationType.Modify, ops[0].Operation);
    }

    // ---- tradeType irány ----------------------------------------------------

    [TestMethod]
    public void MapShipping_DomesticSeller_TradeTypeDomestic()
    {
        var ops = Mapper.MapShipping(CreateShipping(sellerCountry: "HU"), CreateCompany());
        Assert.AreEqual(TradeType.D, ops[0].TradeCard.TradeType, "belföldi (HU) feladó → D");
    }

    [TestMethod]
    public void MapShipping_ForeignSeller_TradeTypeImport()
    {
        var ops = Mapper.MapShipping(CreateShipping(sellerCountry: "DE"), CreateCompany());
        Assert.AreEqual(TradeType.I, ops[0].TradeCard.TradeType, "nem-HU feladó → I (import) — a NAV EKÁER magyar");
    }

    // ---- Tétel-leképezés ----------------------------------------------------

    [TestMethod]
    public void MapShipping_MapsItemFields()
    {
        var item = Mapper.MapShipping(CreateShipping(), CreateCompany())[0].TradeCard.Items[0];

        Assert.AreEqual("08081010", item.ProductVtsz, "productVtsz = ProductDto.Gtin");
        Assert.AreEqual("Alma", item.ProductName);
        Assert.AreEqual(123.5m, item.Weight, "weight = MeasuredGrossWeight (bruttó)");
        Assert.AreEqual(TradeReasonType.A, item.TradeReason, "bejövő áru = beszerzés = A");
        Assert.IsNull(item.Value, "a HUF érték a deviza tisztázásáig nincs kitöltve");
    }

    // ---- Eladó (seller*) ----------------------------------------------------

    [TestMethod]
    public void MapShipping_MapsSellerFromPartner()
    {
        var tradeCard = Mapper.MapShipping(CreateShipping(), CreateCompany())[0].TradeCard;

        Assert.AreEqual("Beszállító Kft", tradeCard.SellerName);
        Assert.AreEqual("12345678-2-42", tradeCard.SellerVatNumber);
        Assert.AreEqual("HU", tradeCard.SellerCountry);
        StringAssert.Contains(tradeCard.SellerAddress, "Budapest", "a sellerAddress a Partner FullAddress-éből jön");
    }

    [TestMethod]
    public void MapShipping_MapsDestinationAndUnloadFromCompany()
    {
        var company = CreateCompany();
        var tradeCard = Mapper.MapShipping(CreateShipping(), company)[0].TradeCard;

        Assert.AreEqual("FruitBank Kft", tradeCard.DestinationName);
        Assert.AreEqual("HU", tradeCard.DestinationCountry);
        StringAssert.Contains(tradeCard.DestinationAddress, "Budapest", "a destinationAddress a company FullAddress-éből jön");
        Assert.AreSame(company.UnloadLocation, tradeCard.UnloadLocation, "a lerakodási hely a cégadatból jön");
    }

    [TestMethod]
    public void MapShipping_MapsCarrierTextFromCargoPartner()
    {
        var tradeCard = Mapper.MapShipping(CreateShipping(), CreateCompany())[0].TradeCard;
        Assert.AreEqual("Fuvaros Zrt", tradeCard.CarrierText);
    }

    // ---- Járművek + rendszám-normalizálás ----------------------------------

    [TestMethod]
    public void MapShipping_NormalizesLicencePlate_RemovesHyphenAndUppercases()
    {
        var tradeCard = Mapper.MapShipping(CreateShipping(plate: "abc-123"), CreateCompany())[0].TradeCard;
        Assert.AreEqual("ABC123", tradeCard.Vehicle!.PlateNumber, "a NAV pattern nem enged kötőjelet, és nagybetűs");
        Assert.AreEqual("HU", tradeCard.Vehicle.Country);
    }

    [TestMethod]
    public void MapShipping_WithTrailer_MapsVehicle2()
    {
        var tradeCard = Mapper.MapShipping(CreateShipping(withTrailer: true), CreateCompany())[0].TradeCard;
        Assert.IsNotNull(tradeCard.Vehicle, "vonó jármű");
        Assert.IsNotNull(tradeCard.Vehicle2, "vontatmány");
        Assert.AreEqual("XYZ789", tradeCard.Vehicle2!.PlateNumber);
    }

    [TestMethod]
    public void MapShipping_NoTrailer_Vehicle2Null()
    {
        var tradeCard = Mapper.MapShipping(CreateShipping(withTrailer: false), CreateCompany())[0].TradeCard;
        Assert.IsNotNull(tradeCard.Vehicle);
        Assert.IsNull(tradeCard.Vehicle2, "nincs pótkocsi → nincs vehicle2");
    }

    // ---- Védőkorlátok -------------------------------------------------------

    [TestMethod]
    public void MapShipping_NullShipping_Throws()
        => Assert.ThrowsExactly<ArgumentNullException>(() => Mapper.MapShipping(null!, CreateCompany()));

    [TestMethod]
    public void MapShipping_NullCompany_Throws()
        => Assert.ThrowsExactly<ArgumentNullException>(() => Mapper.MapShipping(CreateShipping(), null!));
}
