using CashLineERP.Application.Integration;
using CashLineERP.Contracts.Integration;
using CashLineERP.Infrastructure.Persistence.Repositories;

namespace CashLineERP.Api.Tests;

public sealed class InboxMessageProcessingServiceQaTests
{
    [Fact]
    public void Inbox_Message_Can_Be_Received_And_Processed_Against_An_Active_Inbound_Endpoint()
    {
        using var dbContext = QaDbContextFactory.CreateContext();

        var registryService = new IntegrationEndpointRegistryService(new IntegrationEndpointRegistryRepository(dbContext));
        var inboxService = new InboxMessageService(new InboxMessageRepository(dbContext));

        var endpoint = registryService.CreateIntegrationEndpoint(new CreateIntegrationEndpointRequest(
            EndpointName: "Paymob inbound callback",
            IntegrationProviderCode: "PAYMOB",
            EnvironmentCode: "TEST",
            DirectionCode: "INBOUND",
            TransportCode: "WEBHOOK",
            HttpMethodCode: "POST",
            BaseUrl: "https://paymob.test.example",
            RelativePath: "/callbacks/payment",
            AuthenticationModeCode: "SIGNATURE",
            CredentialReference: "secret://paymob/test/signature",
            TimeoutSeconds: 20,
            RetryPolicyCode: "STANDARD",
            MaxRetryCount: 3,
            IsIdempotencyKeyRequired: true,
            Notes: "Inbox baseline endpoint"));
        registryService.SubmitIntegrationEndpoint(endpoint.IntegrationEndpointId, 2);
        registryService.ApproveIntegrationEndpoint(endpoint.IntegrationEndpointId, 4);
        registryService.ActivateIntegrationEndpoint(endpoint.IntegrationEndpointId, 4);

        var receivedMessage = inboxService.ReceiveInboxMessage(2, new ReceiveInboxMessageRequest(
            IntegrationEndpointId: endpoint.IntegrationEndpointId,
            MessageType: "PAYMENT_STATUS",
            ExternalMessageId: "PMB-CB-0001",
            CorrelationKey: "PAYMOB-ORDER-001",
            PayloadText: "{\"status\":\"paid\"}"));

        Assert.Equal("RECEIVED", receivedMessage.StatusCode);
        Assert.Equal("PAYMOB", receivedMessage.IntegrationProviderCode);

        var pendingMessages = inboxService.GetInboxMessages("RECEIVED", "PAYMOB");
        var listedMessage = Assert.Single(pendingMessages);
        Assert.Equal(receivedMessage.InboxMessageId, listedMessage.InboxMessageId);

        var processResult = inboxService.ProcessPendingMessages(new ProcessInboxBatchRequest(
            ProcessorCode: "INBOX_WORKER",
            BatchSize: 10));

        var processedMessage = Assert.Single(processResult.ProcessedMessages);
        Assert.Equal("PROCESSED", processedMessage.StatusCode);
        Assert.Equal("INBOX_WORKER", processedMessage.ProcessedByProcess);
    }

    [Fact]
    public void Inbox_Message_Receipt_Enforces_Idempotency_For_Endpoints_That_Require_It()
    {
        using var dbContext = QaDbContextFactory.CreateContext();

        var registryService = new IntegrationEndpointRegistryService(new IntegrationEndpointRegistryRepository(dbContext));
        var inboxService = new InboxMessageService(new InboxMessageRepository(dbContext));

        var endpoint = registryService.CreateIntegrationEndpoint(new CreateIntegrationEndpointRequest(
            EndpointName: "ETA inbound callback",
            IntegrationProviderCode: "ETA",
            EnvironmentCode: "UAT",
            DirectionCode: "INBOUND",
            TransportCode: "WEBHOOK",
            HttpMethodCode: "POST",
            BaseUrl: "https://eta.uat.example",
            RelativePath: "/callbacks/eta",
            AuthenticationModeCode: "SIGNATURE",
            CredentialReference: "secret://eta/uat/signature",
            TimeoutSeconds: 30,
            RetryPolicyCode: "STANDARD",
            MaxRetryCount: 5,
            IsIdempotencyKeyRequired: true,
            Notes: "ETA inbound callback"));
        registryService.SubmitIntegrationEndpoint(endpoint.IntegrationEndpointId, 2);
        registryService.ApproveIntegrationEndpoint(endpoint.IntegrationEndpointId, 4);
        registryService.ActivateIntegrationEndpoint(endpoint.IntegrationEndpointId, 4);

        var missingKeyException = Assert.Throws<InvalidOperationException>(() =>
            inboxService.ReceiveInboxMessage(2, new ReceiveInboxMessageRequest(
                IntegrationEndpointId: endpoint.IntegrationEndpointId,
                MessageType: "ETA_STATUS",
                ExternalMessageId: null,
                CorrelationKey: null,
                PayloadText: "{\"status\":\"accepted\"}")));
        Assert.Contains("correlation key or external message ID", missingKeyException.Message, StringComparison.OrdinalIgnoreCase);

        inboxService.ReceiveInboxMessage(2, new ReceiveInboxMessageRequest(
            IntegrationEndpointId: endpoint.IntegrationEndpointId,
            MessageType: "ETA_STATUS",
            ExternalMessageId: "ETA-CB-0001",
            CorrelationKey: "ETA-UUID-001",
            PayloadText: "{\"status\":\"accepted\"}"));

        var duplicateException = Assert.Throws<InvalidOperationException>(() =>
            inboxService.ReceiveInboxMessage(2, new ReceiveInboxMessageRequest(
                IntegrationEndpointId: endpoint.IntegrationEndpointId,
                MessageType: "ETA_STATUS",
                ExternalMessageId: "ETA-CB-0001",
                CorrelationKey: "ETA-UUID-001",
                PayloadText: "{\"status\":\"accepted\"}")));
        Assert.Contains("duplicate inbox message", duplicateException.Message, StringComparison.OrdinalIgnoreCase);
    }
}
