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

namespace CashLineERP.Api.Tests;

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

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

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

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

        var createEndpointResponse = await _client.PostAsJsonAsync("/api/v1/integrations/endpoints", new CreateIntegrationEndpointRequest(
            EndpointName: "Notification outbound webhook",
            IntegrationProviderCode: "NOTIFICATION",
            EnvironmentCode: "TEST",
            DirectionCode: "OUTBOUND",
            TransportCode: "WEBHOOK",
            HttpMethodCode: "POST",
            BaseUrl: "https://notify.test.example",
            RelativePath: "/callbacks/status",
            AuthenticationModeCode: "BEARER",
            CredentialReference: "secret://notify/test/bearer",
            TimeoutSeconds: 20,
            RetryPolicyCode: "STANDARD",
            MaxRetryCount: 2,
            IsIdempotencyKeyRequired: false,
            Notes: "Outbox HTTP integration 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 pendingResponse = await _client.GetAsync("/api/v1/integrations/outbox?statusCode=PENDING");
        Assert.Equal(HttpStatusCode.OK, pendingResponse.StatusCode);
        var pendingEvents = await pendingResponse.Content.ReadFromJsonAsync<OutboxEventResponse[]>();
        Assert.NotNull(pendingEvents);
        Assert.NotEmpty(pendingEvents!);

        var reportingEvent = Assert.Single(pendingEvents, item => item.SourceModuleCode == "REPORTING");
        var reportingDetailResponse = await _client.GetAsync($"/api/v1/integrations/outbox/{reportingEvent.OutboxEventId}");
        Assert.Equal(HttpStatusCode.OK, reportingDetailResponse.StatusCode);
        var reportingDetail = await reportingDetailResponse.Content.ReadFromJsonAsync<OutboxEventResponse>();
        Assert.NotNull(reportingDetail);
        Assert.Equal(reportingEvent.EventNumber, reportingDetail!.EventNumber);

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

        var publishResult = await publishResponse.Content.ReadFromJsonAsync<PublishOutboxBatchResultResponse>();
        Assert.NotNull(publishResult);
        Assert.True(publishResult!.PublishedCount >= 2);
        Assert.All(publishResult.PublishedEvents, item => Assert.Equal("PUBLISHED", item.StatusCode));
    }
}
