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

namespace CashLineERP.Api.Tests;

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

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

    [Fact]
    public async Task Aging_Report_Endpoints_Return_AP_And_AR_Bucket_Read_Models_And_Csv_Exports()
    {
        string postedBillNumber;
        string postedInvoiceNumber;

        using (var scope = _factory.Services.CreateScope())
        {
            var goodsReceiptService = scope.ServiceProvider.GetRequiredService<IGoodsReceiptService>();
            var apBillService = scope.ServiceProvider.GetRequiredService<IAccountsPayableBillService>();
            var apPaymentService = scope.ServiceProvider.GetRequiredService<IAccountsPayablePaymentService>();
            var invoiceService = scope.ServiceProvider.GetRequiredService<IAccountsReceivableInvoiceService>();
            var receiptService = scope.ServiceProvider.GetRequiredService<IAccountsReceivableReceiptService>();

            var goodsReceipt = goodsReceiptService.PostGoodsReceipt(
                goodsReceiptService.CreateGoodsReceipt(new CreateGoodsReceiptRequest(
                    BranchId: 1,
                    PurchaseOrderId: 1,
                    SupplierId: 1,
                    ReceivedAtUtc: new DateTime(2026, 4, 5, 9, 0, 0, DateTimeKind.Utc),
                    ReceivedByUserId: 4,
                    InspectionStatus: "ACCEPTED",
                    Lines:
                    [
                        new CreateGoodsReceiptLineRequest(1, 1001, 1, null, 5m, 5m, 0m, "AGING-HTTP-GRN-1", null)
                    ])).GoodsReceiptId,
                4);

            var apBill = apBillService.CreateBill(new CreateAccountsPayableBillRequest(
                SupplierId: 1,
                PurchaseOrderId: 1,
                GoodsReceiptId: goodsReceipt.GoodsReceiptId,
                BillDate: new DateOnly(2026, 4, 5),
                DueDate: new DateOnly(2026, 4, 10),
                CurrencyCode: "EGP",
                Lines:
                [
                    new CreateAccountsPayableBillLineRequest(1, 1001, 5m, "EA", 20m, "VAT14")
                ]));
            apBillService.SubmitBill(apBill.AccountsPayableBillId, 3);
            var dbContext = scope.ServiceProvider.GetRequiredService<CashLineERP.Infrastructure.Persistence.CashLineErpDbContext>();
            var apBillEntity = dbContext.AccountsPayableBills.Single(entry => entry.Id == apBill.AccountsPayableBillId);
            apBillEntity.RecordMatchReview(4, true, 0m, "Aging report HTTP setup");
            apBillEntity.ApproveForPosting(4);
            dbContext.SaveChanges();
            var postedBill = apBillService.PostBill(apBill.AccountsPayableBillId, 4);
            postedBillNumber = postedBill.BillNumber;

            var partialPayment = apPaymentService.CreatePayment(new CreateAccountsPayablePaymentRequest(
                SupplierId: 1,
                PaymentDate: new DateOnly(2026, 4, 15),
                PaymentMethod: "BANK_TRANSFER",
                CurrencyCode: "EGP",
                AmountAmount: 40m,
                ReferenceNumber: "AGING-HTTP-AP-PAY-1",
                Notes: "Partial AP settlement",
                Allocations:
                [
                    new CreateAccountsPayablePaymentAllocationRequest(postedBill.AccountsPayableBillId, 40m, new DateOnly(2026, 4, 15))
                ]));
            apPaymentService.SubmitPayment(partialPayment.AccountsPayablePaymentId, 5);
            apPaymentService.ApprovePayment(partialPayment.AccountsPayablePaymentId, 6);
            apPaymentService.PostPayment(partialPayment.AccountsPayablePaymentId, 6);

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

            var arReceipt = receiptService.CreateReceipt(new CreateAccountsReceivableReceiptRequest(
                CustomerId: 2,
                ReceiptDate: new DateOnly(2026, 4, 20),
                ReceiptMethod: "BANK_TRANSFER",
                CurrencyCode: "EGP",
                AmountAmount: 60m,
                ReferenceNumber: "AGING-HTTP-AR-RCPT-1",
                Notes: "Partial AR settlement",
                Allocations:
                [
                    new CreateAccountsReceivableReceiptAllocationRequest(arInvoice.AccountsReceivableInvoiceId, 60m, new DateOnly(2026, 4, 20))
                ]));
            receiptService.SubmitReceipt(arReceipt.AccountsReceivableReceiptId, 3);
            receiptService.ApproveReceipt(arReceipt.AccountsReceivableReceiptId, 4);
            receiptService.PostReceipt(arReceipt.AccountsReceivableReceiptId, 4);
        }

        await _client.AuthenticateAsFinanceMakerAsync();

        var apReportResponse = await _client.GetAsync("/api/v1/reports/aging/ap?asOfDate=2026-04-25");
        Assert.Equal(HttpStatusCode.OK, apReportResponse.StatusCode);
        var apReport = await apReportResponse.Content.ReadFromJsonAsync<AgingReportResponse>();
        Assert.NotNull(apReport);
        Assert.Equal("AP", apReport!.LedgerSideCode);
        Assert.True(apReport.TotalOutstandingAmount >= 74m);
        Assert.True(apReport.Bucket1To30Amount >= 74m);
        var apRow = Assert.Single(apReport.Rows, row => row.DocumentNumber == postedBillNumber);
        Assert.Equal(74m, apRow.OutstandingAmount);
        Assert.Equal("1_30", apRow.AgingBucketCode);

        var arReportResponse = await _client.GetAsync("/api/v1/reports/aging/ar?asOfDate=2026-04-25");
        Assert.Equal(HttpStatusCode.OK, arReportResponse.StatusCode);
        var arReport = await arReportResponse.Content.ReadFromJsonAsync<AgingReportResponse>();
        Assert.NotNull(arReport);
        Assert.Equal("AR", arReport!.LedgerSideCode);
        Assert.True(arReport.TotalOutstandingAmount >= 54m);
        Assert.True(arReport.Bucket1To30Amount >= 54m);
        var arRow = Assert.Single(arReport.Rows, row => row.DocumentNumber == postedInvoiceNumber);
        Assert.Equal(54m, arRow.OutstandingAmount);
        Assert.Equal("1_30", arRow.AgingBucketCode);

        var apExportResponse = await _client.GetAsync("/api/v1/reports/aging/ap/export?asOfDate=2026-04-25");
        Assert.Equal(HttpStatusCode.OK, apExportResponse.StatusCode);
        Assert.Equal("text/csv", apExportResponse.Content.Headers.ContentType?.MediaType);
        var apCsv = await apExportResponse.Content.ReadAsStringAsync();
        Assert.Contains("LedgerSide,DocumentType,DocumentNumber", apCsv);
        Assert.Contains("AP_BILL", apCsv);

        var arExportResponse = await _client.GetAsync("/api/v1/reports/aging/ar/export?asOfDate=2026-04-25");
        Assert.Equal(HttpStatusCode.OK, arExportResponse.StatusCode);
        Assert.Equal("text/csv", arExportResponse.Content.Headers.ContentType?.MediaType);
        var arCsv = await arExportResponse.Content.ReadAsStringAsync();
        Assert.Contains("LedgerSide,DocumentType,DocumentNumber", arCsv);
        Assert.Contains("ARINV-", arCsv);
    }
}
