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

namespace CashLineERP.Api.Tests;

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

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

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

        var createEndpointResponse = await _client.PostAsJsonAsync("/api/v1/integrations/endpoints", new CreateIntegrationEndpointRequest(
            EndpointName: "Notification inbound callback",
            IntegrationProviderCode: "NOTIFICATION",
            EnvironmentCode: "TEST",
            DirectionCode: "INBOUND",
            TransportCode: "WEBHOOK",
            HttpMethodCode: "POST",
            BaseUrl: "https://notify.test.example",
            RelativePath: "/callbacks/events",
            AuthenticationModeCode: "BEARER",
            CredentialReference: "secret://notify/test/bearer",
            TimeoutSeconds: 20,
            RetryPolicyCode: "STANDARD",
            MaxRetryCount: 2,
            IsIdempotencyKeyRequired: true,
            Notes: "Inbox HTTP 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 receiveResponse = await _client.PostAsJsonAsync("/api/v1/integrations/inbox/receive", new ReceiveInboxMessageRequest(
            IntegrationEndpointId: createdEndpoint.IntegrationEndpointId,
            MessageType: "DELIVERY_STATUS",
            ExternalMessageId: "NTF-CB-0001",
            CorrelationKey: "ORDER-DEL-001",
            PayloadText: "{\"deliveryStatus\":\"delivered\"}"));
        Assert.Equal(HttpStatusCode.OK, receiveResponse.StatusCode);

        var receivedMessage = await receiveResponse.Content.ReadFromJsonAsync<InboxMessageResponse>();
        Assert.NotNull(receivedMessage);
        Assert.Equal("RECEIVED", receivedMessage!.StatusCode);

        var listResponse = await _client.GetAsync("/api/v1/integrations/inbox?statusCode=RECEIVED&integrationProviderCode=NOTIFICATION");
        Assert.Equal(HttpStatusCode.OK, listResponse.StatusCode);
        var inboxMessages = await listResponse.Content.ReadFromJsonAsync<InboxMessageResponse[]>();
        Assert.NotNull(inboxMessages);
        var listedMessage = Assert.Single(inboxMessages!);
        Assert.Equal(receivedMessage.InboxMessageId, listedMessage.InboxMessageId);

        var detailResponse = await _client.GetAsync($"/api/v1/integrations/inbox/{receivedMessage.InboxMessageId}");
        Assert.Equal(HttpStatusCode.OK, detailResponse.StatusCode);
        var detailedMessage = await detailResponse.Content.ReadFromJsonAsync<InboxMessageResponse>();
        Assert.NotNull(detailedMessage);
        Assert.Equal("DELIVERY_STATUS", detailedMessage!.MessageType);

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

        var processResult = await processResponse.Content.ReadFromJsonAsync<ProcessInboxBatchResultResponse>();
        Assert.NotNull(processResult);
        var processedMessage = Assert.Single(processResult!.ProcessedMessages);
        Assert.Equal("PROCESSED", processedMessage.StatusCode);
        Assert.Equal("HTTP_INBOX_WORKER", processedMessage.ProcessedByProcess);
    }
}
