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

namespace CashLineERP.Api.Tests;

public sealed class SupplierStatementAndReconciliationServiceQaTests
{
    [Fact]
    public void Supplier_Statement_And_Reconciliation_Views_Return_Current_AP_Exposure()
    {
        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 statementService = new SupplierStatementService(new SupplierStatementRepository(dbContext));
        var reconciliationService = new SupplierAccountReconciliationService(new SupplierAccountReconciliationRepository(dbContext));

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

        var apBill = apBillService.CreateBill(new CreateAccountsPayableBillRequest(
            SupplierId: 1,
            PurchaseOrderId: 1,
            GoodsReceiptId: goodsReceipt.GoodsReceiptId,
            BillDate: new DateOnly(2026, 5, 5),
            DueDate: new DateOnly(2026, 5, 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, "Supplier statement approval setup");
        apBillEntity.ApproveForPosting(4);
        dbContext.SaveChanges();
        var postedBill = apBillService.PostBill(apBill.AccountsPayableBillId, 4);

        var payment = apPaymentService.CreatePayment(new CreateAccountsPayablePaymentRequest(
            SupplierId: 1,
            PaymentDate: new DateOnly(2026, 5, 15),
            PaymentMethod: "BANK_TRANSFER",
            CurrencyCode: "EGP",
            AmountAmount: 40m,
            ReferenceNumber: "SUP-STMT-PAY-001",
            Notes: "Supplier partial settlement",
            Allocations:
            [
                new CreateAccountsPayablePaymentAllocationRequest(postedBill.AccountsPayableBillId, 40m, new DateOnly(2026, 5, 15))
            ]));
        apPaymentService.SubmitPayment(payment.AccountsPayablePaymentId, 5);
        apPaymentService.ApprovePayment(payment.AccountsPayablePaymentId, 6);
        apPaymentService.PostPayment(payment.AccountsPayablePaymentId, 6);

        var statement = statementService.GenerateStatement(3, new CreateSupplierStatementRequest(
            SupplierId: 1,
            DateFrom: new DateOnly(2026, 5, 1),
            DateTo: new DateOnly(2026, 5, 31),
            CurrencyCode: "EGP"));

        Assert.StartsWith("SSTMT-", statement.StatementNumber);
        Assert.Equal(1L, statement.SupplierId);
        Assert.True(statement.TotalChargeAmount >= 114m);
        Assert.True(statement.TotalSettlementAmount >= 40m);
        Assert.True(statement.ClosingBalanceAmount >= 74m);
        Assert.True(statement.OpenPayableAmount >= 74m);
        Assert.True(statement.OverduePayableAmount >= 74m);
        Assert.Contains(statement.Lines, line => line.DocumentNumber == postedBill.BillNumber && line.ChargeAmount == 114m);
        Assert.Contains(statement.Lines, line => line.DocumentNumber == payment.PaymentNumber);

        var summaries = reconciliationService.GetSummaries(new DateOnly(2026, 5, 31), supplierId: 1, currencyCode: "EGP");
        var summary = Assert.Single(summaries);
        Assert.Equal(statement.SupplierStatementId, summary.LastStatementId);
        Assert.Equal(statement.ClosingBalanceAmount, summary.LastStatementClosingBalanceAmount);
        Assert.Equal(statement.ClosingBalanceAmount, summary.CurrentBalanceAmount);
        Assert.True(summary.OpenPayableAmount >= 74m);
        Assert.Equal(0m, summary.DifferenceAmount);

        var detail = reconciliationService.GetDetail(1, new DateOnly(2026, 5, 31), "EGP");
        Assert.Equal(1L, detail.SupplierId);
        Assert.Equal(statement.SupplierStatementId, detail.LastStatementId);
        Assert.Contains(detail.Lines, line => line.DocumentNumber == postedBill.BillNumber);
        Assert.Contains(detail.Lines, line => line.DocumentType == "AP_PAYMENT");
    }
}
