using System.Net;
using System.Net.Http.Json;
using CashLineERP.Application.Finance;
using CashLineERP.Contracts.Finance;
using CashLineERP.Contracts.Integration;
using CashLineERP.Contracts.Tax;
using Microsoft.Extensions.DependencyInjection;

namespace CashLineERP.Api.Tests;

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

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

    [Fact]
    public async Task Eta_Transmission_Endpoints_Queue_And_Dispatch_Transport_Attempts()
    {
        long invoiceId;

        using (var scope = _factory.Services.CreateScope())
        {
            var invoiceService = scope.ServiceProvider.GetRequiredService<IAccountsReceivableInvoiceService>();

            var invoice = invoiceService.CreateInvoice(new CreateAccountsReceivableInvoiceRequest(
                CustomerId: 2,
                SalesOrderId: 1,
                DispatchOrderId: 1,
                InvoiceType: "TAX",
                InvoiceDate: new DateOnly(2026, 5, 28),
                TaxDate: new DateOnly(2026, 5, 28),
                DueDate: new DateOnly(2026, 6, 7),
                CurrencyCode: "EGP",
                Lines:
                [
                    new CreateAccountsReceivableInvoiceLineRequest(1, 1001, 2m, "EA", 32m, "VAT14")
                ]));

            invoiceId = AccountsReceivableWorkflowTestHelper
                .SubmitApproveAndPostInvoice(invoiceService, invoice.AccountsReceivableInvoiceId)
                .AccountsReceivableInvoiceId;
        }

        await _client.AuthenticateAsFinanceMakerAsync();
        await CreateAndActivateEtaEndpointAsync();

        var submitResponse = await _client.PostAsJsonAsync(
            $"/api/v1/finance/ar-invoices/{invoiceId}/eta-submit",
            new SubmitInvoiceToEtaRequest(ActorUserId: 0, PayloadText: null));
        Assert.Equal(HttpStatusCode.OK, submitResponse.StatusCode);
        var submission = await submitResponse.Content.ReadFromJsonAsync<EtaSubmissionLogResponse>();
        Assert.NotNull(submission);

        var queueResponse = await _client.PostAsync($"/api/v1/finance/ar-invoices/{invoiceId}/eta-submissions/{submission!.EtaSubmissionLogId}/queue-transmission", null);
        Assert.Equal(HttpStatusCode.OK, queueResponse.StatusCode);
        var queued = await queueResponse.Content.ReadFromJsonAsync<EtaTransmissionAttemptResponse>();
        Assert.NotNull(queued);
        Assert.Equal("QUEUED", queued!.StatusCode);

        var dispatchResponse = await _client.PostAsJsonAsync("/api/v1/finance/eta-transmissions/dispatch-batch", new DispatchEtaTransmissionBatchRequest(
            ProcessorCode: "HTTP_ETA_WORKER",
            BatchSize: 10));
        Assert.Equal(HttpStatusCode.OK, dispatchResponse.StatusCode);
        var dispatched = await dispatchResponse.Content.ReadFromJsonAsync<DispatchEtaTransmissionBatchResultResponse>();
        Assert.NotNull(dispatched);
        Assert.Single(dispatched!.Transmissions);
        Assert.Equal("DISPATCHED", dispatched.Transmissions.Single().StatusCode);

        var pollResponse = await _client.PostAsJsonAsync("/api/v1/finance/eta-transmissions/poll-batch", new PollEtaTransmissionBatchRequest(
            ProcessorCode: "HTTP_ETA_POLL_WORKER",
            BatchSize: 10));
        Assert.Equal(HttpStatusCode.OK, pollResponse.StatusCode);
        var polled = await pollResponse.Content.ReadFromJsonAsync<PollEtaTransmissionBatchResultResponse>();
        Assert.NotNull(polled);
        Assert.Single(polled!.Transmissions);
        Assert.Equal("ACCEPTED", polled.Transmissions.Single().StatusCode);

        var listResponse = await _client.GetAsync($"/api/v1/finance/ar-invoices/{invoiceId}/eta-transmissions");
        Assert.Equal(HttpStatusCode.OK, listResponse.StatusCode);
        var transmissions = await listResponse.Content.ReadFromJsonAsync<List<EtaTransmissionAttemptResponse>>();
        Assert.NotNull(transmissions);
        Assert.Contains(transmissions!, item => item.EtaTransmissionAttemptId == queued.EtaTransmissionAttemptId && item.StatusCode == "ACCEPTED");

        var detailResponse = await _client.GetAsync($"/api/v1/finance/eta-transmissions/{queued.EtaTransmissionAttemptId}");
        Assert.Equal(HttpStatusCode.OK, detailResponse.StatusCode);
        var detail = await detailResponse.Content.ReadFromJsonAsync<EtaTransmissionAttemptResponse>();
        Assert.NotNull(detail);
        Assert.Equal("ACCEPTED", detail!.StatusCode);
        Assert.Equal("HTTP_ETA_POLL_WORKER", detail.PolledByProcess);
    }

    private async Task CreateAndActivateEtaEndpointAsync()
    {
        var createResponse = await _client.PostAsJsonAsync("/api/v1/integrations/endpoints", new CreateIntegrationEndpointRequest(
            EndpointName: "HTTP ETA outbound adapter",
            IntegrationProviderCode: "ETA",
            EnvironmentCode: "UAT",
            DirectionCode: "OUTBOUND",
            TransportCode: "REST",
            HttpMethodCode: "POST",
            BaseUrl: "https://eta.uat.example",
            RelativePath: "/documentsubmissions",
            AuthenticationModeCode: "SIGNATURE",
            CredentialReference: "secret://eta/uat/key",
            TimeoutSeconds: 20,
            RetryPolicyCode: "STANDARD",
            MaxRetryCount: 2,
            IsIdempotencyKeyRequired: true,
            Notes: "HTTP ETA transport endpoint"));
        Assert.Equal(HttpStatusCode.OK, createResponse.StatusCode);
        var created = await createResponse.Content.ReadFromJsonAsync<IntegrationEndpointResponse>();
        Assert.NotNull(created);

        Assert.Equal(HttpStatusCode.OK, (await _client.PostAsync($"/api/v1/integrations/endpoints/{created!.IntegrationEndpointId}/submit", null)).StatusCode);
        await _client.AuthenticateAsFinanceCheckerAsync();
        Assert.Equal(HttpStatusCode.OK, (await _client.PostAsync($"/api/v1/integrations/endpoints/{created.IntegrationEndpointId}/approve", null)).StatusCode);
        Assert.Equal(HttpStatusCode.OK, (await _client.PostAsync($"/api/v1/integrations/endpoints/{created.IntegrationEndpointId}/activate", null)).StatusCode);
        await _client.AuthenticateAsFinanceMakerAsync();
    }
}
