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

namespace CashLineERP.Api.Tests;

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

        var reportingService = new CoreReportingService(new CoreReportingRepository(dbContext));
        var outboxService = new OutboxEventService(new OutboxEventRepository(dbContext));
        var deadLetterService = new DeadLetterService(new DeadLetterRepository(dbContext));
        var registryService = new IntegrationEndpointRegistryService(new IntegrationEndpointRegistryRepository(dbContext));
        var inboxService = new InboxMessageService(new InboxMessageRepository(dbContext));

        var snapshot = reportingService.GenerateReportingSnapshot(2, new CreateReportingSnapshotRequest(
            ReportCode: "CORE_OPERATIONS",
            DateFrom: new DateOnly(2026, 4, 1),
            DateTo: new DateOnly(2026, 4, 30),
            AsOfDate: null,
            Notes: "Dead-letter outbox baseline"));

        var outboxEvent = Assert.Single(outboxService.GetOutboxEvents("PENDING", "REPORTING"));
        var deadLetteredOutbox = outboxService.MoveOutboxEventToDeadLetter(outboxEvent.OutboxEventId, 2, new DeadLetterQueueItemRequest(
            ReasonText: "Publisher adapter unavailable"));
        Assert.Equal("DEAD_LETTER", deadLetteredOutbox.StatusCode);

        var endpoint = registryService.CreateIntegrationEndpoint(new CreateIntegrationEndpointRequest(
            EndpointName: "Dead-letter inbox callback",
            IntegrationProviderCode: "NOTIFICATION",
            EnvironmentCode: "TEST",
            DirectionCode: "INBOUND",
            TransportCode: "WEBHOOK",
            HttpMethodCode: "POST",
            BaseUrl: "https://notify.test.example",
            RelativePath: "/callbacks/dead-letter",
            AuthenticationModeCode: "BEARER",
            CredentialReference: "secret://notify/test/bearer",
            TimeoutSeconds: 20,
            RetryPolicyCode: "STANDARD",
            MaxRetryCount: 2,
            IsIdempotencyKeyRequired: true,
            Notes: "Dead-letter inbox endpoint"));
        registryService.SubmitIntegrationEndpoint(endpoint.IntegrationEndpointId, 2);
        registryService.ApproveIntegrationEndpoint(endpoint.IntegrationEndpointId, 4);
        registryService.ActivateIntegrationEndpoint(endpoint.IntegrationEndpointId, 4);

        var inboxMessage = inboxService.ReceiveInboxMessage(2, new ReceiveInboxMessageRequest(
            IntegrationEndpointId: endpoint.IntegrationEndpointId,
            MessageType: "STATUS_UPDATE",
            ExternalMessageId: "NTF-DL-0001",
            CorrelationKey: "ORDER-DL-001",
            PayloadText: "{\"status\":\"queued\"}"));
        var deadLetteredInbox = inboxService.MoveInboxMessageToDeadLetter(inboxMessage.InboxMessageId, 2, new DeadLetterQueueItemRequest(
            ReasonText: "Inbound handler failed"));
        Assert.Equal("DEAD_LETTER", deadLetteredInbox.StatusCode);

        var deadLetters = deadLetterService.GetDeadLetters();
        Assert.Contains(deadLetters, item => item.QueueType == "OUTBOX" && item.ItemId == deadLetteredOutbox.OutboxEventId);
        Assert.Contains(deadLetters, item => item.QueueType == "INBOX" && item.ItemId == deadLetteredInbox.InboxMessageId);

        var replayedOutbox = outboxService.ReplayOutboxEvent(deadLetteredOutbox.OutboxEventId, 2, new ReplayDeadLetterQueueItemRequest(
            ReplayReasonText: "Retry after transport recovery",
            DelaySeconds: 0));
        Assert.Equal("RETRY", replayedOutbox.StatusCode);

        var replayedInbox = inboxService.ReplayInboxMessage(deadLetteredInbox.InboxMessageId, 2, new ReplayDeadLetterQueueItemRequest(
            ReplayReasonText: "Retry after handler fix",
            DelaySeconds: 0));
        Assert.Equal("RETRY", replayedInbox.StatusCode);

        var publishResult = outboxService.PublishPendingEvents(new PublishOutboxBatchRequest(
            PublisherCode: "DEAD_LETTER_WORKER",
            BatchSize: 10));
        Assert.Contains(publishResult.PublishedEvents, item => item.OutboxEventId == deadLetteredOutbox.OutboxEventId);

        var processResult = inboxService.ProcessPendingMessages(new ProcessInboxBatchRequest(
            ProcessorCode: "DEAD_LETTER_INBOX_WORKER",
            BatchSize: 10));
        Assert.Contains(processResult.ProcessedMessages, item => item.InboxMessageId == deadLetteredInbox.InboxMessageId);
    }
}
