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

namespace CashLineERP.Api.Tests;

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

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

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

        var createBillResponse = await _client.PostAsJsonAsync("/api/v1/procurement/ap-bills", new CreateAccountsPayableBillRequest(
            SupplierId: 1,
            PurchaseOrderId: 1,
            GoodsReceiptId: 1,
            BillDate: new DateOnly(2026, 4, 23),
            DueDate: new DateOnly(2026, 4, 30),
            CurrencyCode: "EGP",
            Lines:
            [
                new CreateAccountsPayableBillLineRequest(1, 1001, 50m, "EA", 24m, "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();

        var createPaymentResponse = await _client.PostAsJsonAsync("/api/v1/finance/ap-payments", new CreateAccountsPayablePaymentRequest(
            SupplierId: 1,
            PaymentDate: new DateOnly(2026, 4, 24),
            PaymentMethod: "BANK_TRANSFER",
            CurrencyCode: "EGP",
            AmountAmount: postedBill!.TotalAmount,
            ReferenceNumber: "SUPP-PAY-HTTP-0001",
            Notes: "Original supplier payment",
            Allocations:
            [
                new CreateAccountsPayablePaymentAllocationRequest(postedBill.AccountsPayableBillId, postedBill.TotalAmount, new DateOnly(2026, 4, 24))
            ]));
        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());

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

        var reversePaymentResponse = await _client.PostAsJsonAsync(
            $"/api/v1/finance/ap-payments/{payment.AccountsPayablePaymentId}/reverse",
            new ReverseAccountsPayablePaymentRequest(
                ReversalDate: new DateOnly(2026, 4, 25),
                ReasonCode: "BANK_ERROR",
                Notes: "Supplier payment must be re-issued."));
        Assert.True(reversePaymentResponse.IsSuccessStatusCode, await reversePaymentResponse.Content.ReadAsStringAsync());

        var reversedPayment = await reversePaymentResponse.Content.ReadFromJsonAsync<AccountsPayablePaymentResponse>();
        Assert.NotNull(reversedPayment);
        Assert.Equal("REVERSED", reversedPayment!.StatusCode);

        var repostPaymentResponse = await _client.PostAsJsonAsync(
            $"/api/v1/finance/ap-payments/{payment.AccountsPayablePaymentId}/repost",
            new RepostAccountsPayablePaymentRequest(
                PaymentDate: new DateOnly(2026, 4, 25),
                PaymentMethod: "BANK_TRANSFER",
                ReferenceNumber: "SUPP-PAY-HTTP-0001-R1",
                Notes: "Replacement supplier payment.",
                Allocations:
                [
                    new CreateAccountsPayablePaymentAllocationRequest(postedBill.AccountsPayableBillId, postedBill.TotalAmount, new DateOnly(2026, 4, 25))
                ]));
        Assert.True(repostPaymentResponse.IsSuccessStatusCode, await repostPaymentResponse.Content.ReadAsStringAsync());

        var replacementPayment = await repostPaymentResponse.Content.ReadFromJsonAsync<AccountsPayablePaymentResponse>();
        Assert.NotNull(replacementPayment);
        Assert.Equal(payment.AccountsPayablePaymentId, replacementPayment!.RepostedFromPaymentId);

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

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

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

        var repostedPayment = await postReplacementResponse.Content.ReadFromJsonAsync<AccountsPayablePaymentResponse>();
        Assert.NotNull(repostedPayment);
        Assert.Equal("POSTED", repostedPayment!.StatusCode);
        Assert.NotNull(repostedPayment.GeneralLedgerBatchId);
    }
}
