using CashLineERP.Application.Finance;
using CashLineERP.Application.Procurement;
using CashLineERP.Application.Reporting;
using CashLineERP.Contracts.Finance;
using CashLineERP.Contracts.Procurement;
using CashLineERP.Infrastructure.Persistence.Repositories;
using CashLineERP.Domain.Procurement;

namespace CashLineERP.Api.Tests;

public sealed class AgingReportServiceQaTests
{
    [Fact]
    public void Aging_Reports_Return_AP_And_AR_Buckets_From_Outstanding_Balances()
    {
        using var dbContext = QaDbContextFactory.CreateContext();

        var goodsReceiptService = new GoodsReceiptService(new GoodsReceiptRepository(dbContext));
        var apBillService = new AccountsPayableBillService(new AccountsPayableBillRepository(dbContext));
        var apPaymentService = new AccountsPayablePaymentService(new AccountsPayablePaymentRepository(dbContext));
        var invoiceService = new AccountsReceivableInvoiceService(new AccountsReceivableInvoiceRepository(dbContext));
        var receiptService = new AccountsReceivableReceiptService(new AccountsReceivableReceiptRepository(dbContext));
        var reportingService = new CoreReportingService(new CoreReportingRepository(dbContext));

        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-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 apBillEntity = dbContext.AccountsPayableBills.Single(entry => entry.Id == apBill.AccountsPayableBillId);
        apBillEntity.RecordMatchReview(4, true, 0m, "Aging report approval setup");
        apBillEntity.ApproveForPosting(4);
        dbContext.SaveChanges();
        var postedBill = apBillService.PostBill(apBill.AccountsPayableBillId, 4);

        var partialPayment = apPaymentService.CreatePayment(new CreateAccountsPayablePaymentRequest(
            SupplierId: 1,
            PaymentDate: new DateOnly(2026, 4, 15),
            PaymentMethod: "BANK_TRANSFER",
            CurrencyCode: "EGP",
            AmountAmount: 40m,
            ReferenceNumber: "AGING-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);

        var arReceipt = receiptService.CreateReceipt(new CreateAccountsReceivableReceiptRequest(
            CustomerId: 2,
            ReceiptDate: new DateOnly(2026, 4, 20),
            ReceiptMethod: "BANK_TRANSFER",
            CurrencyCode: "EGP",
            AmountAmount: 60m,
            ReferenceNumber: "AGING-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);

        var apAging = reportingService.GetAccountsPayableAgingReport(new DateOnly(2026, 4, 25));
        Assert.Equal("AP", apAging.LedgerSideCode);
        Assert.True(apAging.DocumentCount >= 1);
        Assert.True(apAging.PartyCount >= 1);
        Assert.True(apAging.TotalOutstandingAmount >= 74m);
        Assert.True(apAging.Bucket1To30Amount >= 74m);
        var apRow = Assert.Single(apAging.Rows, row => row.DocumentNumber == postedBill.BillNumber);
        Assert.Equal("AP_BILL", apRow.DocumentType);
        Assert.Equal(74m, apRow.OutstandingAmount);
        Assert.Equal(15, apRow.DaysPastDue);
        Assert.Equal("1_30", apRow.AgingBucketCode);

        var arAging = reportingService.GetAccountsReceivableAgingReport(new DateOnly(2026, 4, 25));
        Assert.Equal("AR", arAging.LedgerSideCode);
        Assert.True(arAging.DocumentCount >= 1);
        Assert.True(arAging.PartyCount >= 1);
        Assert.True(arAging.TotalOutstandingAmount >= 54m);
        Assert.True(arAging.Bucket1To30Amount >= 54m);
        var arRow = Assert.Single(arAging.Rows, row => row.DocumentNumber == arInvoice.InvoiceNumber);
        Assert.Equal("TAX", arRow.DocumentType);
        Assert.Equal(54m, arRow.OutstandingAmount);
        Assert.Equal(13, arRow.DaysPastDue);
        Assert.Equal("1_30", arRow.AgingBucketCode);
    }
}
