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

namespace CashLineERP.Api.Tests;

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

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

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

        var createReturnResponse = await _client.PostAsJsonAsync("/api/v1/procurement/purchase-returns", new CreatePurchaseReturnRequest(
            BranchId: 1,
            SupplierId: 1,
            PurchaseOrderId: 1,
            GoodsReceiptId: 1,
            ReturnDate: new DateOnly(2026, 5, 8),
            ReturnWarehouseId: 1,
            ReasonCode: "SUPPLIER_REJECTION",
            Notes: "HTTP purchase return flow.",
            Lines:
            [
                new CreatePurchaseReturnLineRequest(1, 1, 1001, 3m, null, "BATCH-1001-A", null, "Returned via HTTP")
            ]));

        Assert.True(createReturnResponse.IsSuccessStatusCode, await createReturnResponse.Content.ReadAsStringAsync());
        var purchaseReturn = await createReturnResponse.Content.ReadFromJsonAsync<PurchaseReturnResponse>();
        Assert.NotNull(purchaseReturn);

        var submitReturnResponse = await _client.PostAsync($"/api/v1/procurement/purchase-returns/{purchaseReturn!.PurchaseReturnId}/submit", null);
        Assert.True(submitReturnResponse.IsSuccessStatusCode, await submitReturnResponse.Content.ReadAsStringAsync());

        var postReturnResponse = await _client.PostAsync($"/api/v1/procurement/purchase-returns/{purchaseReturn.PurchaseReturnId}/post", null);
        Assert.True(postReturnResponse.IsSuccessStatusCode, await postReturnResponse.Content.ReadAsStringAsync());

        var issueDebitNoteResponse = await _client.PostAsJsonAsync($"/api/v1/procurement/purchase-returns/{purchaseReturn.PurchaseReturnId}/issue-debit-note", new IssuePurchaseReturnDebitNoteRequest(
            ActorUserId: 4,
            BillDate: new DateOnly(2026, 5, 8),
            DueDate: new DateOnly(2026, 5, 21)));
        Assert.True(issueDebitNoteResponse.IsSuccessStatusCode, await issueDebitNoteResponse.Content.ReadAsStringAsync());

        var returnedWithDebitNote = await issueDebitNoteResponse.Content.ReadFromJsonAsync<PurchaseReturnResponse>();
        Assert.NotNull(returnedWithDebitNote);
        Assert.NotNull(returnedWithDebitNote!.DebitNoteBillId);

        var debitNoteResponse = await _client.GetAsync($"/api/v1/procurement/ap-bills/{returnedWithDebitNote.DebitNoteBillId}");
        Assert.True(debitNoteResponse.IsSuccessStatusCode, await debitNoteResponse.Content.ReadAsStringAsync());
        var debitNote = await debitNoteResponse.Content.ReadFromJsonAsync<AccountsPayableBillResponse>();
        Assert.NotNull(debitNote);
        Assert.Equal("DEBIT_NOTE", debitNote!.BillType);

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

        var matchResponse = await _client.GetAsync($"/api/v1/procurement/ap-bills/{debitNote.AccountsPayableBillId}/match");
        Assert.True(matchResponse.IsSuccessStatusCode, await matchResponse.Content.ReadAsStringAsync());
        var match = await matchResponse.Content.ReadFromJsonAsync<AccountsPayableBillMatchResponse>();
        Assert.NotNull(match);
        Assert.True(match!.IsEligibleForApproval);

        await _client.AuthenticateAsFinanceCheckerAsync();

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

        var postDebitNoteResponse = await _client.PostAsync($"/api/v1/procurement/ap-bills/{debitNote.AccountsPayableBillId}/post", null);
        Assert.True(postDebitNoteResponse.IsSuccessStatusCode, await postDebitNoteResponse.Content.ReadAsStringAsync());
        var postedDebitNote = await postDebitNoteResponse.Content.ReadFromJsonAsync<AccountsPayableBillResponse>();
        Assert.NotNull(postedDebitNote);
        Assert.Equal("POSTED", postedDebitNote!.StatusCode);
        Assert.Equal("DEBIT_NOTE", postedDebitNote.BillType);

        var movementResponse = await _client.GetAsync("/api/v1/inventory/movements");
        Assert.True(movementResponse.IsSuccessStatusCode, await movementResponse.Content.ReadAsStringAsync());
        var movements = await movementResponse.Content.ReadFromJsonAsync<List<InventoryMovementResponse>>();
        Assert.NotNull(movements);
        Assert.Contains(movements!, movement => movement.MovementType == "PURCHASE_RETURN_ISSUE" && movement.QuantityMoved == 3m);

        var glResponse = await _client.GetAsync("/api/v1/finance/gl-batches");
        Assert.True(glResponse.IsSuccessStatusCode, await glResponse.Content.ReadAsStringAsync());
        var batches = await glResponse.Content.ReadFromJsonAsync<List<GeneralLedgerBatchResponse>>();
        Assert.NotNull(batches);
        Assert.Contains(batches!, batch => batch.BatchType == "AP_DEBIT_NOTE" && batch.SourceDocumentId == debitNote.AccountsPayableBillId);
    }
}
