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

namespace CashLineERP.Api.Tests;

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

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

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

        var createResponse = await _client.PostAsJsonAsync("/api/v1/finance/close-journals", new CreateFinanceCloseJournalRequest(
            AccountingPeriodId: 1,
            BranchId: 1,
            JournalClassCode: "ADJUSTMENT",
            PostingDate: new DateOnly(2026, 4, 29),
            DocumentDate: new DateOnly(2026, 4, 29),
            Notes: "HTTP finance close adjustment.",
            Lines:
            [
                new CreateFinanceCloseJournalLineRequest(6201, 1, null, null, null, 90m, 0m, "EGP", 1m, "Close adjustment debit"),
                new CreateFinanceCloseJournalLineRequest(2201, 1, null, null, null, 0m, 90m, "EGP", 1m, "Close adjustment credit")
            ]));

        Assert.True(createResponse.IsSuccessStatusCode, await createResponse.Content.ReadAsStringAsync());
        var created = await createResponse.Content.ReadFromJsonAsync<FinanceCloseJournalResponse>();
        Assert.NotNull(created);

        var submitResponse = await _client.PostAsync($"/api/v1/finance/close-journals/{created!.FinanceCloseJournalId}/submit", null);
        Assert.True(submitResponse.IsSuccessStatusCode, await submitResponse.Content.ReadAsStringAsync());

        await _client.AuthenticateAsFinanceCheckerAsync();

        var approveResponse = await _client.PostAsync($"/api/v1/finance/close-journals/{created.FinanceCloseJournalId}/approve", null);
        Assert.True(approveResponse.IsSuccessStatusCode, await approveResponse.Content.ReadAsStringAsync());

        var postResponse = await _client.PostAsync($"/api/v1/finance/close-journals/{created.FinanceCloseJournalId}/post", null);
        Assert.True(postResponse.IsSuccessStatusCode, await postResponse.Content.ReadAsStringAsync());
        var posted = await postResponse.Content.ReadFromJsonAsync<FinanceCloseJournalResponse>();
        Assert.NotNull(posted);
        Assert.Equal("POSTED", posted!.StatusCode);

        var readinessResponse = await _client.GetAsync("/api/v1/finance/accounting-periods/1/close-readiness");
        Assert.True(readinessResponse.IsSuccessStatusCode, await readinessResponse.Content.ReadAsStringAsync());
        var readiness = await readinessResponse.Content.ReadFromJsonAsync<AccountingPeriodCloseReadinessResponse>();
        Assert.NotNull(readiness);
        Assert.Equal(0, readiness!.OpenCloseJournalCount);

        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 == "FIN_CLOSE_JOURNAL" && batch.SourceDocumentId == created.FinanceCloseJournalId);
    }

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

        var createCloseJournalResponse = await _client.PostAsJsonAsync("/api/v1/finance/close-journals", new CreateFinanceCloseJournalRequest(
            AccountingPeriodId: 1,
            BranchId: 1,
            JournalClassCode: "ADJUSTMENT",
            PostingDate: new DateOnly(2026, 4, 28),
            DocumentDate: new DateOnly(2026, 4, 28),
            Notes: "HTTP month-end adjustment journal.",
            Lines:
            [
                new CreateFinanceCloseJournalLineRequest(6201, 1, null, null, null, 75m, 0m, "EGP", 1m, "Adjustment debit"),
                new CreateFinanceCloseJournalLineRequest(2201, 1, null, null, null, 0m, 75m, "EGP", 1m, "Adjustment credit")
            ]));
        Assert.True(createCloseJournalResponse.IsSuccessStatusCode, await createCloseJournalResponse.Content.ReadAsStringAsync());
        var createdJournal = await createCloseJournalResponse.Content.ReadFromJsonAsync<FinanceCloseJournalResponse>();
        Assert.NotNull(createdJournal);

        var submitJournalResponse = await _client.PostAsync($"/api/v1/finance/close-journals/{createdJournal!.FinanceCloseJournalId}/submit", null);
        Assert.True(submitJournalResponse.IsSuccessStatusCode, await submitJournalResponse.Content.ReadAsStringAsync());

        await _client.AuthenticateAsFinanceCheckerAsync();

        var approveJournalResponse = await _client.PostAsync($"/api/v1/finance/close-journals/{createdJournal.FinanceCloseJournalId}/approve", null);
        Assert.True(approveJournalResponse.IsSuccessStatusCode, await approveJournalResponse.Content.ReadAsStringAsync());

        var postJournalResponse = await _client.PostAsync($"/api/v1/finance/close-journals/{createdJournal.FinanceCloseJournalId}/post", null);
        Assert.True(postJournalResponse.IsSuccessStatusCode, await postJournalResponse.Content.ReadAsStringAsync());

        await _client.AuthenticateAsFinanceMakerAsync();

        var createAdjustmentResponse = await _client.PostAsJsonAsync("/api/v1/inventory/adjustments", new CreateInventoryAdjustmentRequest(
            BranchId: 1,
            WarehouseId: 1,
            AdjustmentDate: new DateOnly(2026, 4, 28),
            ReasonCode: "COUNT_VARIANCE",
            Notes: "HTTP draft adjustment for month-end review.",
            Lines:
            [
                new CreateInventoryAdjustmentLineRequest(1001, null, -1m, "EA", 20m, "AVAILABLE", "LOT-HTTP-APR-01", null, "Pending write-down")
            ]));
        Assert.True(createAdjustmentResponse.IsSuccessStatusCode, await createAdjustmentResponse.Content.ReadAsStringAsync());

        var readinessResponse = await _client.GetAsync("/api/v1/finance/accounting-periods/1/close-readiness");
        Assert.True(readinessResponse.IsSuccessStatusCode, await readinessResponse.Content.ReadAsStringAsync());
        var readiness = await readinessResponse.Content.ReadFromJsonAsync<AccountingPeriodCloseReadinessResponse>();
        Assert.NotNull(readiness);
        Assert.True(readiness!.OpenInventoryAdjustmentCount >= 1);
        Assert.True(readiness.PostedAdjustmentCloseJournalCount >= 1);

        var monthEndReviewResponse = await _client.GetAsync("/api/v1/finance/accounting-periods/1/month-end-review");
        Assert.True(monthEndReviewResponse.IsSuccessStatusCode, await monthEndReviewResponse.Content.ReadAsStringAsync());
        var review = await monthEndReviewResponse.Content.ReadFromJsonAsync<AccountingPeriodMonthEndReviewResponse>();
        Assert.NotNull(review);
        Assert.True(review!.CloseReadiness.PostedAdjustmentCloseJournalCount >= 1);
        Assert.Contains(review.CloseJournalClassSummaries, summary =>
            summary.JournalClassCode == "ADJUSTMENT" &&
            summary.PostedCount >= 1);
        Assert.Contains(review.OpenItems, item =>
            item.DocumentType == "INV_ADJUSTMENT" &&
            item.DocumentNumber.StartsWith("INVADJ-", StringComparison.OrdinalIgnoreCase));
    }
}
