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

namespace FruitBankHybrid.Shared.Tests.Ekaer;

/// <summary>
/// Unit tesztek a <see cref="EkaerReportability"/> bejelentés-kötelezettség-eldöntésére. Tisztán memóriában felépített
/// <see cref="EkaerConsignment"/>-eken fut (nincs hálózat/DB), determinisztikus. Küszöb: 200 kg / 250 000 Ft.
/// </summary>
[TestClass]
public sealed class EkaerReportabilityTests
{
    private static readonly EkaerSettings Settings = new()
    {
        EurHufRate = 356,
        ThresholdWeightKg = 200,
        ThresholdValueHuf = 250_000,
    };

    private static EkaerConsignment Consignment(string? sellerCountry, string? buyerCountry, params EkaerLine[] lines) => new()
    {
        Seller = new EkaerEndpoint { Name = "Feladó", CountryCode = sellerCountry },
        Buyer = new EkaerEndpoint { Name = "Címzett", CountryCode = buyerCountry },
        Lines = lines,
    };

    private static EkaerLine Line(double weightKg, long? valueHuf) =>
        new() { ExternalId = "1", WeightKg = weightKg, ValueHuf = valueHuf, TradeReason = TradeReasonType.A };

    // ---- Belföld + küszöb ----------------------------------------------------

    [TestMethod]
    public void Domestic_BelowBothThresholds_NotRequired()
    {
        var result = EkaerReportability.Evaluate(Consignment("HU", "HU", Line(100, 100_000)), Settings);
        Assert.AreEqual(EkaerObligation.NotRequired, result.Obligation);
        Assert.AreEqual(0, result.Errors.Count, "küszöb alatt NINCS üzenet (nem hiba)");
    }

    [TestMethod]
    public void Domestic_WeightAtOrOverThreshold_Required()
    {
        var result = EkaerReportability.Evaluate(Consignment("HU", "HU", Line(200, 0)), Settings);
        Assert.AreEqual(EkaerObligation.Required, result.Obligation, "a tömeg eléri a küszöböt → kötelező (VAGY-logika)");
    }

    [TestMethod]
    public void Domestic_ValueOverThreshold_Required()
    {
        var result = EkaerReportability.Evaluate(Consignment("HU", "HU", Line(10, 300_000)), Settings);
        Assert.AreEqual(EkaerObligation.Required, result.Obligation, "az érték átlépi a küszöböt → kötelező");
    }

    [TestMethod]
    public void Domestic_AggregatedOverThreshold_Required()
    {
        // Egyenként 200 kg ALATT, EGYÜTT fölötte → kötelező. Ez a (Shipping, Partner)-aggregálás lényege.
        var result = EkaerReportability.Evaluate(Consignment("HU", "HU", Line(120, 0), Line(120, 0)), Settings);
        Assert.AreEqual(EkaerObligation.Required, result.Obligation);
    }

    // ---- Külföld (a két országkód eltér) → küszöb nélkül kötelező ------------

    [TestMethod]
    public void CrossBorder_BelowThreshold_StillRequired()
    {
        var result = EkaerReportability.Evaluate(Consignment("DE", "HU", Line(1, 1)), Settings);
        Assert.AreEqual(EkaerObligation.Required, result.Obligation, "eltérő országkód → mindig kötelező, küszöb nélkül");
    }

    [TestMethod]
    public void SameForeignCountryBothEnds_TreatedAsDomesticThreshold()
    {
        // Mindkét vég azonos (nem HU) ország → NEM határátlépő → a küszöb dönt.
        var result = EkaerReportability.Evaluate(Consignment("DE", "DE", Line(1, 1)), Settings);
        Assert.AreEqual(EkaerObligation.NotRequired, result.Obligation);
    }

    // ---- Adathiba: érvénytelen/hiányzó országkód → DataError CSAK küszöb alatt ----

    [TestMethod]
    public void BelowThreshold_MissingSellerCountry_DataError()
    {
        // Küszöb alatt MÁR számít az ország (foreign-vs-belföld) — hiányzó országkód → nem dönthető el → DataError.
        var result = EkaerReportability.Evaluate(Consignment(null, "HU", Line(10, 1000)), Settings);
        Assert.AreEqual(EkaerObligation.DataError, result.Obligation);
        Assert.IsTrue(result.Errors.Count > 0, "a hiányzó országkódot jelezni kell a felhasználónak");
    }

    [TestMethod]
    public void BelowThreshold_InvalidSellerCountry_NotIso2_DataError()
    {
        // Teljes név (nem ISO-2) → érvénytelen → küszöb alatt nem dönthető el → DataError.
        var result = EkaerReportability.Evaluate(Consignment("Magyarország", "HU", Line(10, 1000)), Settings);
        Assert.AreEqual(EkaerObligation.DataError, result.Obligation);
    }

    [TestMethod]
    public void BelowThreshold_MissingBuyerCountry_DataError()
    {
        var result = EkaerReportability.Evaluate(Consignment("HU", "", Line(10, 1000)), Settings);
        Assert.AreEqual(EkaerObligation.DataError, result.Obligation);
    }

    [TestMethod]
    public void OverThreshold_InvalidCountry_Required_NotDataError()
    {
        // Küszöb FELETT (tömeg 500 ≥ 200) a kötelezettség az országkódtól FÜGGETLEN → a sor létrejön (a hibát a
        // generate-validálás jelzi), NEM DataError.
        var result = EkaerReportability.Evaluate(Consignment(null, "Magyarország", Line(500, 0)), Settings);
        Assert.AreEqual(EkaerObligation.Required, result.Obligation);
        Assert.AreEqual(0, result.Errors.Count);
    }

    // ---- Hibás / üres adatok (robusztusság) ----------------------------------

    [TestMethod]
    public void NoLines_Domestic_NotRequired()
    {
        // Üres szállítmány (nincs tétel) → tömeg/érték 0 → küszöb alatt → belföld → nem kötelező (NEM dob).
        var result = EkaerReportability.Evaluate(Consignment("HU", "HU"), Settings);
        Assert.AreEqual(EkaerObligation.NotRequired, result.Obligation);
    }

    [TestMethod]
    public void BothCountriesInvalid_BelowThreshold_DataError_WithTwoMessages()
    {
        var result = EkaerReportability.Evaluate(Consignment(null, "", Line(10, 1000)), Settings);
        Assert.AreEqual(EkaerObligation.DataError, result.Obligation);
        Assert.AreEqual(2, result.Errors.Count, "mindkét hibás országkódot külön jelezni kell");
    }

    [TestMethod]
    public void NullLineValue_HandledAsZero_WeightDecides()
    {
        // Hiányzó (null) tétel-érték (pl. külföldi deviza árfolyam nélkül) → 0-ként számít, NEM dob; a tömeg dönt.
        var result = EkaerReportability.Evaluate(Consignment("HU", "HU", Line(500, null)), Settings);
        Assert.AreEqual(EkaerObligation.Required, result.Obligation, "a tömeg átlépi a küszöböt — a null érték nem akadály");
    }
}
