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 BankTransferBatchPaymentServiceQaTests
{
    [Fact]
    public void Bank_Transfer_Batch_Posts_Approved_AP_Payments_In_One_Controlled_Action()
    {
        using var dbContext = QaDbContextFactory.CreateContext();

        var billService = new AccountsPayableBillService(new AccountsPayableBillRepository(dbContext));
        var paymentService = new AccountsPayablePaymentService(new AccountsPayablePaymentRepository(dbContext));
        var batchService = new BankTransferBatchService(new BankTransferBatchRepository(dbContext));

        AccountsPayableBillResponse CreatePostedBill(DateOnly billDate, int purchaseOrderLineId, long itemId, decimal quantity, string uom, decimal unitPrice)
        {
            var createdBill = billService.CreateBill(new CreateAccountsPayableBillRequest(
                SupplierId: 1,
                PurchaseOrderId: 1,
                GoodsReceiptId: 1,
                BillDate: billDate,
                DueDate: billDate.AddDays(10),
                CurrencyCode: "EGP",
                Lines:
                [
                    new CreateAccountsPayableBillLineRequest(purchaseOrderLineId, itemId, quantity, uom, unitPrice, "VAT14")
                ]));

            billService.SubmitBill(createdBill.AccountsPayableBillId, 3);
            billService.ApproveMatch(createdBill.AccountsPayableBillId, 4);
            return billService.PostBill(createdBill.AccountsPayableBillId, 4);
        }

        var postedBillOne = CreatePostedBill(new DateOnly(2026, 4, 26), 1, 1001, 10m, "EA", 24m);
        var postedBillTwo = CreatePostedBill(new DateOnly(2026, 4, 26), 2, 1002, 5m, "BOX", 50m);

        AccountsPayablePaymentResponse CreateApprovedPayment(AccountsPayableBillResponse bill, string referenceNumber, DateOnly paymentDate)
        {
            var createdPayment = paymentService.CreatePayment(new CreateAccountsPayablePaymentRequest(
                SupplierId: 1,
                PaymentDate: paymentDate,
                PaymentMethod: "BANK_TRANSFER",
                CurrencyCode: "EGP",
                AmountAmount: bill.TotalAmount,
                ReferenceNumber: referenceNumber,
                Notes: "Bank transfer batch payment",
                Allocations:
                [
                    new CreateAccountsPayablePaymentAllocationRequest(bill.AccountsPayableBillId, bill.TotalAmount, paymentDate)
                ]));

            paymentService.SubmitPayment(createdPayment.AccountsPayablePaymentId, 3);
            return paymentService.ApprovePayment(createdPayment.AccountsPayablePaymentId, 4);
        }

        var approvedPaymentOne = CreateApprovedPayment(postedBillOne, "SUPP-BATCH-0001", new DateOnly(2026, 4, 27));
        var approvedPaymentTwo = CreateApprovedPayment(postedBillTwo, "SUPP-BATCH-0002", new DateOnly(2026, 4, 27));

        var createdBatch = batchService.CreateBatch(new CreateBankTransferBatchRequest(
            BankAccountCode: "CIB-EGP-AP-001",
            TransferDate: new DateOnly(2026, 4, 27),
            CurrencyCode: "EGP",
            AccountsPayablePaymentIds:
            [
                approvedPaymentOne.AccountsPayablePaymentId,
                approvedPaymentTwo.AccountsPayablePaymentId
            ]));

        Assert.Equal("DRAFT", createdBatch.StatusCode);
        Assert.Equal(2, createdBatch.TotalPaymentCount);
        Assert.Equal(approvedPaymentOne.AmountAmount + approvedPaymentTwo.AmountAmount, createdBatch.TotalAmount);

        var submittedBatch = batchService.SubmitBatch(createdBatch.BankTransferBatchId, 3);
        Assert.Equal("SUBMITTED", submittedBatch.StatusCode);

        var approvedBatch = batchService.ApproveBatch(createdBatch.BankTransferBatchId, 4);
        Assert.Equal("APPROVED", approvedBatch.StatusCode);

        var postedBatch = batchService.PostBatch(createdBatch.BankTransferBatchId, 4);
        Assert.Equal("POSTED", postedBatch.StatusCode);
        Assert.Equal(2, postedBatch.Lines.Count);

        var refreshedPaymentOne = paymentService.GetPayment(approvedPaymentOne.AccountsPayablePaymentId);
        var refreshedPaymentTwo = paymentService.GetPayment(approvedPaymentTwo.AccountsPayablePaymentId);
        Assert.NotNull(refreshedPaymentOne);
        Assert.NotNull(refreshedPaymentTwo);
        Assert.Equal("POSTED", refreshedPaymentOne!.StatusCode);
        Assert.Equal("POSTED", refreshedPaymentTwo!.StatusCode);
        Assert.NotNull(refreshedPaymentOne.GeneralLedgerBatchId);
        Assert.NotNull(refreshedPaymentTwo.GeneralLedgerBatchId);
    }
}
