using System.ComponentModel.DataAnnotations;
using System.Net;
using System.Text;
using AyCode.Services.Nav;
using AyCode.Services.Nav.Ekaer;
using AyCode.Services.Nav.Ekaer.Models;
using TradeType = AyCode.Services.Nav.Ekaer.Models.Common.TradeType;

namespace AyCode.Services.Tests.Nav;

/// <summary>
/// Az <see cref="EkaerSubmitService"/> tesztjei: a validate → send sorrend a valódi <see cref="EkaerManageService"/>
/// fölött, fake <see cref="HttpMessageHandler"/>-rel (nincs valódi hálózat) és stub validátorral.
/// </summary>
[TestClass]
public sealed class EkaerSubmitServiceTests
{
    // ---- Test doubles -------------------------------------------------------

    private sealed class FakeHttpMessageHandler(HttpStatusCode status, string body) : HttpMessageHandler
    {
        public int CallCount { get; private set; }
        public string? LastRequestBody { get; private set; }

        protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            CallCount++;
            if (request.Content is not null)
                LastRequestBody = await request.Content.ReadAsStringAsync(cancellationToken);
            return new HttpResponseMessage(status) { Content = new StringContent(body, Encoding.UTF8, "text/xml") };
        }
    }

    private sealed class StubValidator(IReadOnlyList<ValidationResult> errors) : IEkaerTradeCardValidator
    {
        public IReadOnlyList<ValidationResult> Validate(TradeCardOperationType operation) => errors;
        public IReadOnlyList<ValidationResult> Validate(IEnumerable<TradeCardOperationType> operations) => errors;
    }

    private sealed class FakeCredentials : INavCredentials
    {
        public string User => "u";
        public string Password => "p";
        public string SigningKey => "k";
        public string TaxNumber => "12345678";
        public string BaseUrl => "https://test.example";
    }

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

    private static EkaerSubmitService CreateSut(IReadOnlyList<ValidationResult> validationErrors, FakeHttpMessageHandler handler)
    {
        var manageService = new EkaerManageService(new HttpClient(handler), new FakeCredentials());
        return new EkaerSubmitService(manageService, new StubValidator(validationErrors));
    }

    private static string OkResponseXml()
        => NavXmlHelper.Serialize(new ManageTradeCardsResponse { Result = new BaseResultType { FuncCode = FunctionCodeType.Ok } });

    private static TradeCardOperationType SomeOperation()
        => new() { Index = 1, Operation = OperationType.Create, TradeCard = new TradeCardType { TradeType = TradeType.I } };

    // ---- Tesztek ------------------------------------------------------------

    [TestMethod]
    public async Task SubmitAsync_ValidationFails_DoesNotSend()
    {
        var handler = new FakeHttpMessageHandler(HttpStatusCode.OK, OkResponseXml());
        var sut = CreateSut([new ValidationResult("teszthiba")], handler);

        var result = await sut.SubmitAsync([SomeOperation()]);

        Assert.IsFalse(result.IsValid);
        Assert.AreEqual(1, result.ValidationErrors.Count);
        Assert.IsNull(result.Response);
        Assert.AreEqual(0, handler.CallCount, "validációs hiba esetén NEM mehet ki kérés a NAV-nak");
    }

    [TestMethod]
    public async Task SubmitAsync_Valid_SendsAndReturnsResponse()
    {
        var handler = new FakeHttpMessageHandler(HttpStatusCode.OK, OkResponseXml());
        var sut = CreateSut([], handler);

        var result = await sut.SubmitAsync([SomeOperation()]);

        Assert.IsTrue(result.IsValid);
        Assert.AreEqual(1, handler.CallCount, "érvényes esetben egy kérés megy ki");
        Assert.IsNotNull(result.Response);
        Assert.AreEqual(0, result.ValidationErrors.Count);
    }

    [TestMethod]
    public async Task SubmitAsync_Valid_RequestContainsOperations()
    {
        var handler = new FakeHttpMessageHandler(HttpStatusCode.OK, OkResponseXml());
        var sut = CreateSut([], handler);

        await sut.SubmitAsync([SomeOperation()]);

        Assert.IsNotNull(handler.LastRequestBody);
        StringAssert.Contains(handler.LastRequestBody, "tradeCardOperation", "a beküldött XML tartalmazza a műveleteket");
    }

    [TestMethod]
    public async Task SubmitAsync_NavHttpError_PropagatesNavReportException()
    {
        var handler = new FakeHttpMessageHandler(HttpStatusCode.InternalServerError, "boom");
        var sut = CreateSut([], handler);

        await Assert.ThrowsExactlyAsync<NavReportException>(() => sut.SubmitAsync([SomeOperation()]));
    }

    [TestMethod]
    public async Task SubmitAsync_NullOperations_Throws()
    {
        var handler = new FakeHttpMessageHandler(HttpStatusCode.OK, OkResponseXml());
        var sut = CreateSut([], handler);

        await Assert.ThrowsExactlyAsync<ArgumentNullException>(() => sut.SubmitAsync(null!));
    }
}
