using System.Net.Http.Json;
using CashLineERP.Contracts.Finance;
using CashLineERP.Contracts.Procurement;

namespace CashLineERP.Api.Tests;

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

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

    [Fact]
    public async Task Bank_Transfer_Batch_Can_Be_Submitted_Approved_And_Posted()
    {
        await _client.AuthenticateAsFinanceMakerAsync();

        async Task<AccountsPayableBillResponse> CreatePostedBillAsync(DateOnly billDate, int poLineId, long itemId, decimal quantity, string uom, decimal unitPrice)
        {
            var createBillResponse = await _client.PostAsJsonAsync("/api/v1/procurement/ap-bills", new CreateAccountsPayableBillRequest(
                SupplierId: 1,
                PurchaseOrderId: 1,
                GoodsReceiptId: 1,
                BillDate: billDate,
                DueDate: billDate.AddDays(10),
                CurrencyCode: "EGP",
                Lines:
                [
                    new CreateAccountsPayableBillLineRequest(poLineId, itemId, quantity, uom, unitPrice, "VAT14")
                ]));
            Assert.True(createBillResponse.IsSuccessStatusCode, await createBillResponse.Content.ReadAsStringAsync());
            var bill = await createBillResponse.Content.ReadFromJsonAsync<AccountsPayableBillResponse>();
            Assert.NotNull(bill);

            var submitBillResponse = await _client.PostAsync($"/api/v1/procurement/ap-bills/{bill!.AccountsPayableBillId}/submit", null);
            Assert.True(submitBillResponse.IsSuccessStatusCode, await submitBillResponse.Content.ReadAsStringAsync());

            await _client.AuthenticateAsFinanceCheckerAsync();
            var approveMatchResponse = await _client.PostAsync($"/api/v1/procurement/ap-bills/{bill.AccountsPayableBillId}/approve-match", null);
            Assert.True(approveMatchResponse.IsSuccessStatusCode, await approveMatchResponse.Content.ReadAsStringAsync());

            var postBillResponse = await _client.PostAsync($"/api/v1/procurement/ap-bills/{bill.AccountsPayableBillId}/post", null);
            Assert.True(postBillResponse.IsSuccessStatusCode, await postBillResponse.Content.ReadAsStringAsync());
            var postedBill = await postBillResponse.Content.ReadFromJsonAsync<AccountsPayableBillResponse>();
            Assert.NotNull(postedBill);

            await _client.AuthenticateAsFinanceMakerAsync();
            return postedBill!;
        }

        async Task<AccountsPayablePaymentResponse> CreateApprovedPaymentAsync(AccountsPayableBillResponse bill, string referenceNumber, DateOnly paymentDate)
        {
            var createPaymentResponse = await _client.PostAsJsonAsync("/api/v1/finance/ap-payments", new CreateAccountsPayablePaymentRequest(
                SupplierId: 1,
                PaymentDate: paymentDate,
                PaymentMethod: "BANK_TRANSFER",
                CurrencyCode: "EGP",
                AmountAmount: bill.TotalAmount,
                ReferenceNumber: referenceNumber,
                Notes: "Bank transfer batch payment",
                Allocations:
                [
                    new CreateAccountsPayablePaymentAllocationRequest(bill.AccountsPayableBillId, bill.TotalAmount, paymentDate)
                ]));
            Assert.True(createPaymentResponse.IsSuccessStatusCode, await createPaymentResponse.Content.ReadAsStringAsync());
            var payment = await createPaymentResponse.Content.ReadFromJsonAsync<AccountsPayablePaymentResponse>();
            Assert.NotNull(payment);

            var submitPaymentResponse = await _client.PostAsync($"/api/v1/finance/ap-payments/{payment!.AccountsPayablePaymentId}/submit", null);
            Assert.True(submitPaymentResponse.IsSuccessStatusCode, await submitPaymentResponse.Content.ReadAsStringAsync());

            await _client.AuthenticateAsFinanceCheckerAsync();
            var approvePaymentResponse = await _client.PostAsync($"/api/v1/finance/ap-payments/{payment.AccountsPayablePaymentId}/approve", null);
            Assert.True(approvePaymentResponse.IsSuccessStatusCode, await approvePaymentResponse.Content.ReadAsStringAsync());

            await _client.AuthenticateAsFinanceMakerAsync();
            var refreshedPaymentResponse = await _client.GetAsync($"/api/v1/finance/ap-payments/{payment.AccountsPayablePaymentId}");
            Assert.True(refreshedPaymentResponse.IsSuccessStatusCode, await refreshedPaymentResponse.Content.ReadAsStringAsync());
            var approvedPayment = await refreshedPaymentResponse.Content.ReadFromJsonAsync<AccountsPayablePaymentResponse>();
            Assert.NotNull(approvedPayment);
            return approvedPayment!;
        }

        var postedBillOne = await CreatePostedBillAsync(new DateOnly(2026, 4, 28), 1, 1001, 10m, "EA", 24m);
        var postedBillTwo = await CreatePostedBillAsync(new DateOnly(2026, 4, 28), 2, 1002, 5m, "BOX", 50m);
        var approvedPaymentOne = await CreateApprovedPaymentAsync(postedBillOne, "SUPP-BATCH-HTTP-0001", new DateOnly(2026, 4, 29));
        var approvedPaymentTwo = await CreateApprovedPaymentAsync(postedBillTwo, "SUPP-BATCH-HTTP-0002", new DateOnly(2026, 4, 29));

        var createBatchResponse = await _client.PostAsJsonAsync("/api/v1/finance/bank-transfer-batches", new CreateBankTransferBatchRequest(
            BankAccountCode: "CIB-EGP-AP-001",
            TransferDate: new DateOnly(2026, 4, 29),
            CurrencyCode: "EGP",
            AccountsPayablePaymentIds:
            [
                approvedPaymentOne.AccountsPayablePaymentId,
                approvedPaymentTwo.AccountsPayablePaymentId
            ]));
        Assert.True(createBatchResponse.IsSuccessStatusCode, await createBatchResponse.Content.ReadAsStringAsync());
        var batch = await createBatchResponse.Content.ReadFromJsonAsync<BankTransferBatchResponse>();
        Assert.NotNull(batch);
        Assert.Equal(2, batch!.TotalPaymentCount);

        var submitBatchResponse = await _client.PostAsync($"/api/v1/finance/bank-transfer-batches/{batch.BankTransferBatchId}/submit", null);
        Assert.True(submitBatchResponse.IsSuccessStatusCode, await submitBatchResponse.Content.ReadAsStringAsync());

        await _client.AuthenticateAsFinanceCheckerAsync();
        var approveBatchResponse = await _client.PostAsync($"/api/v1/finance/bank-transfer-batches/{batch.BankTransferBatchId}/approve", null);
        Assert.True(approveBatchResponse.IsSuccessStatusCode, await approveBatchResponse.Content.ReadAsStringAsync());

        var postBatchResponse = await _client.PostAsync($"/api/v1/finance/bank-transfer-batches/{batch.BankTransferBatchId}/post", null);
        Assert.True(postBatchResponse.IsSuccessStatusCode, await postBatchResponse.Content.ReadAsStringAsync());
        var postedBatch = await postBatchResponse.Content.ReadFromJsonAsync<BankTransferBatchResponse>();
        Assert.NotNull(postedBatch);
        Assert.Equal("POSTED", postedBatch!.StatusCode);

        var refreshedPaymentOneResponse = await _client.GetAsync($"/api/v1/finance/ap-payments/{approvedPaymentOne.AccountsPayablePaymentId}");
        var refreshedPaymentTwoResponse = await _client.GetAsync($"/api/v1/finance/ap-payments/{approvedPaymentTwo.AccountsPayablePaymentId}");
        Assert.True(refreshedPaymentOneResponse.IsSuccessStatusCode, await refreshedPaymentOneResponse.Content.ReadAsStringAsync());
        Assert.True(refreshedPaymentTwoResponse.IsSuccessStatusCode, await refreshedPaymentTwoResponse.Content.ReadAsStringAsync());
        var refreshedPaymentOne = await refreshedPaymentOneResponse.Content.ReadFromJsonAsync<AccountsPayablePaymentResponse>();
        var refreshedPaymentTwo = await refreshedPaymentTwoResponse.Content.ReadFromJsonAsync<AccountsPayablePaymentResponse>();
        Assert.NotNull(refreshedPaymentOne);
        Assert.NotNull(refreshedPaymentTwo);
        Assert.Equal("POSTED", refreshedPaymentOne!.StatusCode);
        Assert.Equal("POSTED", refreshedPaymentTwo!.StatusCode);
    }
}
