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

namespace CashLineERP.Api.Tests;

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

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

    [Fact]
    public async Task Customer_Statement_Endpoints_Generate_And_Log_Delivery()
    {
        using (var scope = _factory.Services.CreateScope())
        {
            var invoiceService = scope.ServiceProvider.GetRequiredService<IAccountsReceivableInvoiceService>();
            var receiptService = scope.ServiceProvider.GetRequiredService<IAccountsReceivableReceiptService>();

            var postedInvoice = AccountsReceivableWorkflowTestHelper.SubmitApproveAndPostInvoice(
                invoiceService,
                invoiceService.CreateInvoice(new CreateAccountsReceivableInvoiceRequest(
                    CustomerId: 2,
                    SalesOrderId: 1,
                    DispatchOrderId: 1,
                    InvoiceType: "TAX",
                    InvoiceDate: new DateOnly(2026, 5, 11),
                    TaxDate: new DateOnly(2026, 5, 11),
                    DueDate: new DateOnly(2026, 5, 21),
                    CurrencyCode: "EGP",
                    Lines:
                    [
                        new CreateAccountsReceivableInvoiceLineRequest(1, 1001, 2m, "EA", 50m, "VAT14")
                    ])).AccountsReceivableInvoiceId);

            AccountsReceivableWorkflowTestHelper.SubmitApproveAndPostReceipt(
                receiptService,
                receiptService.CreateReceipt(new CreateAccountsReceivableReceiptRequest(
                    CustomerId: 2,
                    ReceiptDate: new DateOnly(2026, 5, 16),
                    ReceiptMethod: "BANK_TRANSFER",
                    CurrencyCode: "EGP",
                    AmountAmount: 60m,
                    ReferenceNumber: "HTTP-CUST-STMT-RCPT-001",
                    Notes: "HTTP customer statement receipt",
                    Allocations:
                    [
                        new CreateAccountsReceivableReceiptAllocationRequest(postedInvoice.AccountsReceivableInvoiceId, 60m, new DateOnly(2026, 5, 16))
                    ])).AccountsReceivableReceiptId);
        }

        await _client.AuthenticateAsFinanceMakerAsync();

        var generateResponse = await _client.PostAsJsonAsync("/api/v1/finance/customer-statements", new CreateCustomerStatementRequest(
            CustomerId: 2,
            DateFrom: new DateOnly(2026, 5, 1),
            DateTo: new DateOnly(2026, 5, 31),
            CurrencyCode: "EGP"));
        Assert.Equal(HttpStatusCode.OK, generateResponse.StatusCode);
        var statement = await generateResponse.Content.ReadFromJsonAsync<CustomerStatementResponse>();
        Assert.NotNull(statement);
        Assert.StartsWith("CSTMT-", statement!.StatementNumber);
        Assert.Equal(2L, statement.CustomerId);
        Assert.True(statement.ClosingBalanceAmount >= 54m);
        Assert.Contains(statement.Lines, line => line.DocumentType == "TAX");
        Assert.Contains(statement.Lines, line => line.DocumentType == "AR_RECEIPT");

        var logResponse = await _client.PostAsJsonAsync($"/api/v1/finance/customer-statements/{statement.CustomerStatementId}/delivery-logs", new RecordCustomerStatementDeliveryRequest(
            DeliveredAtUtc: new DateTime(2026, 5, 31, 15, 30, 0, DateTimeKind.Utc),
            ChannelCode: "portal",
            RecipientAddress: "customer-admin",
            DeliveryStatusCode: "published",
            Notes: "Statement published to portal"));
        Assert.Equal(HttpStatusCode.OK, logResponse.StatusCode);
        var deliveryLog = await logResponse.Content.ReadFromJsonAsync<CustomerStatementDeliveryLogResponse>();
        Assert.NotNull(deliveryLog);
        Assert.Equal("PORTAL", deliveryLog!.ChannelCode);

        var listResponse = await _client.GetAsync("/api/v1/finance/customer-statements?customerId=2");
        Assert.Equal(HttpStatusCode.OK, listResponse.StatusCode);
        var statements = await listResponse.Content.ReadFromJsonAsync<List<CustomerStatementSummaryResponse>>();
        Assert.NotNull(statements);
        Assert.Contains(statements!, item => item.CustomerStatementId == statement.CustomerStatementId && item.DeliveryLogCount == 1);

        var detailResponse = await _client.GetAsync($"/api/v1/finance/customer-statements/{statement.CustomerStatementId}");
        Assert.Equal(HttpStatusCode.OK, detailResponse.StatusCode);
        var detail = await detailResponse.Content.ReadFromJsonAsync<CustomerStatementResponse>();
        Assert.NotNull(detail);
        Assert.Single(detail!.DeliveryLogs);

        var logListResponse = await _client.GetAsync($"/api/v1/finance/customer-statements/{statement.CustomerStatementId}/delivery-logs");
        Assert.Equal(HttpStatusCode.OK, logListResponse.StatusCode);
        var logs = await logListResponse.Content.ReadFromJsonAsync<List<CustomerStatementDeliveryLogResponse>>();
        Assert.NotNull(logs);
        Assert.Single(logs!);
    }
}
