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

namespace CashLineERP.Api.Tests;

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

        var cashAccountService = new CashAccountService(new CashAccountRepository(dbContext));
        var treasuryTransferService = new TreasuryTransferService(new TreasuryTransferRepository(dbContext));

        var destinationAccount = cashAccountService.CreateCashAccount(new CreateCashAccountRequest(
            AccountCode: "BANK-EGP-002",
            AccountName: "Secondary EGP Bank",
            AccountType: "BANK",
            CurrencyCode: "EGP",
            BranchId: 1,
            OpeningBalanceAmount: 2000m));

        var sourceAccountBefore = cashAccountService.GetCashAccount(2);
        Assert.NotNull(sourceAccountBefore);

        var createdTransfer = treasuryTransferService.CreateTreasuryTransfer(new CreateTreasuryTransferRequest(
            FromCashAccountId: 2,
            ToCashAccountId: destinationAccount.CashAccountId,
            TransferDate: new DateOnly(2026, 4, 30),
            CurrencyCode: "EGP",
            AmountAmount: 1500m,
            ReferenceNumber: "TREASURY-0001",
            Notes: "Treasury balancing transfer"));

        Assert.Equal("DRAFT", createdTransfer.StatusCode);

        var submittedTransfer = treasuryTransferService.SubmitTreasuryTransfer(createdTransfer.TreasuryTransferId, 3);
        Assert.Equal("SUBMITTED", submittedTransfer.StatusCode);

        var approvedTransfer = treasuryTransferService.ApproveTreasuryTransfer(createdTransfer.TreasuryTransferId, 4);
        Assert.Equal("APPROVED", approvedTransfer.StatusCode);

        var postedTransfer = treasuryTransferService.PostTreasuryTransfer(createdTransfer.TreasuryTransferId, 4);
        Assert.Equal("POSTED", postedTransfer.StatusCode);
        Assert.NotNull(postedTransfer.GeneralLedgerBatchId);

        var sourceAccountAfter = cashAccountService.GetCashAccount(2);
        var destinationAccountAfter = cashAccountService.GetCashAccount(destinationAccount.CashAccountId);
        Assert.NotNull(sourceAccountAfter);
        Assert.NotNull(destinationAccountAfter);
        Assert.Equal(sourceAccountBefore!.CurrentBalanceAmount - 1500m, sourceAccountAfter!.CurrentBalanceAmount);
        Assert.Equal(destinationAccount.OpeningBalanceAmount + 1500m, destinationAccountAfter!.CurrentBalanceAmount);
    }

    [Fact]
    public void Treasury_Transfer_Preserves_Base_Currency_Amounts_For_Non_Base_Currency()
    {
        using var dbContext = QaDbContextFactory.CreateContext();

        var cashAccountService = new CashAccountService(new CashAccountRepository(dbContext));
        var treasuryTransferService = new TreasuryTransferService(new TreasuryTransferRepository(dbContext));

        var sourceAccount = cashAccountService.CreateCashAccount(new CreateCashAccountRequest(
            AccountCode: "BANK-USD-001",
            AccountName: "Primary USD Bank",
            AccountType: "BANK",
            CurrencyCode: "USD",
            BranchId: 1,
            OpeningBalanceAmount: 1000m));
        var destinationAccount = cashAccountService.CreateCashAccount(new CreateCashAccountRequest(
            AccountCode: "BANK-USD-002",
            AccountName: "Secondary USD Bank",
            AccountType: "BANK",
            CurrencyCode: "USD",
            BranchId: 1,
            OpeningBalanceAmount: 250m));

        var createdTransfer = treasuryTransferService.CreateTreasuryTransfer(new CreateTreasuryTransferRequest(
            FromCashAccountId: sourceAccount.CashAccountId,
            ToCashAccountId: destinationAccount.CashAccountId,
            TransferDate: new DateOnly(2026, 4, 30),
            CurrencyCode: "USD",
            AmountAmount: 10m,
            ReferenceNumber: "TREASURY-USD-0001",
            Notes: "USD treasury transfer"));

        Assert.Equal("EGP", createdTransfer.BaseCurrencyCode);
        Assert.Equal(49.50m, createdTransfer.FxRateToBase);
        Assert.Equal(495m, createdTransfer.BaseAmount);
    }
}
