using System.Net;
using System.Net.Http.Json;
using CashLineERP.Contracts.Integration;
using CashLineERP.Contracts.Reporting;

namespace CashLineERP.Api.Tests;

public sealed class DeadLetterReplayQaTests : IClassFixture<ApiTestFactory>
{
    private readonly HttpClient _client;

    public DeadLetterReplayQaTests(ApiTestFactory factory)
    {
        _client = factory.CreateClient();
    }

    [Fact]
    public async Task Dead_Letter_And_Replay_Endpoints_Work_End_To_End()
    {
        await _client.AuthenticateAsInternalAsync();

        var snapshotResponse = await _client.PostAsJsonAsync("/api/v1/reports/snapshots", new CreateReportingSnapshotRequest(
            ReportCode: "CORE_FINANCE",
            DateFrom: new DateOnly(2026, 4, 1),
            DateTo: new DateOnly(2026, 4, 30),
            AsOfDate: null,
            Notes: "Dead-letter HTTP outbox"));
        Assert.Equal(HttpStatusCode.OK, snapshotResponse.StatusCode);

        var pendingOutboxResponse = await _client.GetAsync("/api/v1/integrations/outbox?statusCode=PENDING&sourceModuleCode=REPORTING");
        Assert.Equal(HttpStatusCode.OK, pendingOutboxResponse.StatusCode);
        var pendingOutbox = await pendingOutboxResponse.Content.ReadFromJsonAsync<OutboxEventResponse[]>();
        Assert.NotNull(pendingOutbox);
        var outboxEvent = Assert.Single(pendingOutbox!);

        var deadLetterOutboxResponse = await _client.PostAsJsonAsync($"/api/v1/integrations/outbox/{outboxEvent.OutboxEventId}/dead-letter", new DeadLetterQueueItemRequest(
            ReasonText: "HTTP dead-letter outbox"));
        Assert.Equal(HttpStatusCode.OK, deadLetterOutboxResponse.StatusCode);

        var createEndpointResponse = await _client.PostAsJsonAsync("/api/v1/integrations/endpoints", new CreateIntegrationEndpointRequest(
            EndpointName: "Dead-letter HTTP inbox",
            IntegrationProviderCode: "PAYMOB",
            EnvironmentCode: "TEST",
            DirectionCode: "INBOUND",
            TransportCode: "WEBHOOK",
            HttpMethodCode: "POST",
            BaseUrl: "https://paymob.test.example",
            RelativePath: "/callbacks/dead-letter",
            AuthenticationModeCode: "SIGNATURE",
            CredentialReference: "secret://paymob/test/signature",
            TimeoutSeconds: 20,
            RetryPolicyCode: "STANDARD",
            MaxRetryCount: 2,
            IsIdempotencyKeyRequired: true,
            Notes: "Dead-letter HTTP inbox endpoint"));
        Assert.Equal(HttpStatusCode.OK, createEndpointResponse.StatusCode);
        var createdEndpoint = await createEndpointResponse.Content.ReadFromJsonAsync<IntegrationEndpointResponse>();
        Assert.NotNull(createdEndpoint);

        var submitResponse = await _client.PostAsync($"/api/v1/integrations/endpoints/{createdEndpoint!.IntegrationEndpointId}/submit", null);
        Assert.Equal(HttpStatusCode.OK, submitResponse.StatusCode);
        await _client.AuthenticateAsFinanceCheckerAsync();
        var approveResponse = await _client.PostAsync($"/api/v1/integrations/endpoints/{createdEndpoint.IntegrationEndpointId}/approve", null);
        Assert.Equal(HttpStatusCode.OK, approveResponse.StatusCode);
        var activateResponse = await _client.PostAsync($"/api/v1/integrations/endpoints/{createdEndpoint.IntegrationEndpointId}/activate", null);
        Assert.Equal(HttpStatusCode.OK, activateResponse.StatusCode);

        await _client.AuthenticateAsInternalAsync();
        var receiveInboxResponse = await _client.PostAsJsonAsync("/api/v1/integrations/inbox/receive", new ReceiveInboxMessageRequest(
            IntegrationEndpointId: createdEndpoint.IntegrationEndpointId,
            MessageType: "PAYMENT_STATUS",
            ExternalMessageId: "PMB-DL-0001",
            CorrelationKey: "ORDER-PMB-001",
            PayloadText: "{\"status\":\"captured\"}"));
        Assert.Equal(HttpStatusCode.OK, receiveInboxResponse.StatusCode);
        var inboxMessage = await receiveInboxResponse.Content.ReadFromJsonAsync<InboxMessageResponse>();
        Assert.NotNull(inboxMessage);

        var deadLetterInboxResponse = await _client.PostAsJsonAsync($"/api/v1/integrations/inbox/{inboxMessage!.InboxMessageId}/dead-letter", new DeadLetterQueueItemRequest(
            ReasonText: "HTTP dead-letter inbox"));
        Assert.Equal(HttpStatusCode.OK, deadLetterInboxResponse.StatusCode);

        var deadLettersResponse = await _client.GetAsync("/api/v1/integrations/dead-letters");
        Assert.Equal(HttpStatusCode.OK, deadLettersResponse.StatusCode);
        var deadLetters = await deadLettersResponse.Content.ReadFromJsonAsync<DeadLetterQueueItemResponse[]>();
        Assert.NotNull(deadLetters);
        Assert.Contains(deadLetters!, item => item.QueueType == "OUTBOX" && item.ItemId == outboxEvent.OutboxEventId);
        Assert.Contains(deadLetters!, item => item.QueueType == "INBOX" && item.ItemId == inboxMessage.InboxMessageId);

        var replayOutboxResponse = await _client.PostAsJsonAsync($"/api/v1/integrations/outbox/{outboxEvent.OutboxEventId}/replay", new ReplayDeadLetterQueueItemRequest(
            ReplayReasonText: "HTTP replay outbox",
            DelaySeconds: 0));
        Assert.Equal(HttpStatusCode.OK, replayOutboxResponse.StatusCode);

        var replayInboxResponse = await _client.PostAsJsonAsync($"/api/v1/integrations/inbox/{inboxMessage.InboxMessageId}/replay", new ReplayDeadLetterQueueItemRequest(
            ReplayReasonText: "HTTP replay inbox",
            DelaySeconds: 0));
        Assert.Equal(HttpStatusCode.OK, replayInboxResponse.StatusCode);

        var publishResponse = await _client.PostAsJsonAsync("/api/v1/integrations/outbox/publish-batch", new PublishOutboxBatchRequest(
            PublisherCode: "HTTP_DEAD_LETTER_WORKER",
            BatchSize: 10));
        Assert.Equal(HttpStatusCode.OK, publishResponse.StatusCode);

        var processResponse = await _client.PostAsJsonAsync("/api/v1/integrations/inbox/process-batch", new ProcessInboxBatchRequest(
            ProcessorCode: "HTTP_DEAD_LETTER_INBOX_WORKER",
            BatchSize: 10));
        Assert.Equal(HttpStatusCode.OK, processResponse.StatusCode);
    }
}
