using Akka.Actor;
using Akka.TestKit.Xunit2;
using ScadaLink.Commons.Messages.RemoteQuery;

namespace ScadaLink.SiteEventLogging.Tests;

/// <summary>
/// Regression tests for SiteEventLogging-010: the actor message contract of
/// <see cref="EventLogHandlerActor"/> was previously untested.
/// </summary>
public class EventLogHandlerActorTests : TestKit
{
    /// <summary>Test double returning a canned response and recording the request.</summary>
    private sealed class FakeQueryService : IEventLogQueryService
    {
        private readonly Func<EventLogQueryRequest, EventLogQueryResponse> _handler;
        public EventLogQueryRequest? LastRequest { get; private set; }

        public FakeQueryService(Func<EventLogQueryRequest, EventLogQueryResponse> handler)
            => _handler = handler;

        public EventLogQueryResponse ExecuteQuery(EventLogQueryRequest request)
        {
            LastRequest = request;
            return _handler(request);
        }
    }

    private static EventLogQueryRequest MakeRequest(string correlationId) => new(
        CorrelationId: correlationId,
        SiteId: "site-1",
        From: null,
        To: null,
        EventType: null,
        Severity: null,
        InstanceId: null,
        KeywordFilter: null,
        ContinuationToken: null,
        PageSize: 500,
        Timestamp: DateTimeOffset.UtcNow);

    private static EventLogQueryResponse MakeResponse(EventLogQueryRequest req, bool success = true) => new(
        CorrelationId: req.CorrelationId,
        SiteId: req.SiteId,
        Entries: [],
        ContinuationToken: null,
        HasMore: false,
        Success: success,
        ErrorMessage: success ? null : "boom",
        Timestamp: DateTimeOffset.UtcNow);

    [Fact]
    public void Actor_RepliesToSender_WithQueryResponse()
    {
        var fake = new FakeQueryService(req => MakeResponse(req));
        var actor = Sys.ActorOf(Props.Create(() => new EventLogHandlerActor(fake)));

        var request = MakeRequest("corr-1");
        actor.Tell(request, TestActor);

        var response = ExpectMsg<EventLogQueryResponse>();
        Assert.Equal("corr-1", response.CorrelationId);
        Assert.Equal("site-1", response.SiteId);
        Assert.True(response.Success);
        Assert.Same(request, fake.LastRequest);
    }

    [Fact]
    public void Actor_PropagatesQueryServiceErrorResponse_ToSender()
    {
        var fake = new FakeQueryService(req => MakeResponse(req, success: false));
        var actor = Sys.ActorOf(Props.Create(() => new EventLogHandlerActor(fake)));

        actor.Tell(MakeRequest("corr-2"), TestActor);

        var response = ExpectMsg<EventLogQueryResponse>();
        Assert.False(response.Success);
        Assert.Equal("corr-2", response.CorrelationId);
        Assert.Equal("boom", response.ErrorMessage);
    }
}
