using System.Globalization;
using Baya.Application.Features.Payments.Commands.ConfirmPaymentAndPostLedger;
using Baya.Application.Features.Payments.Commands.InitiatePayment;
using Baya.Application.Features.Payments.Queries.GetNursePayableBalance;
using Baya.Domain.Entities.Payments;

namespace Baya.Test.Foundation.Payments;

public class NursePayableBalanceTests
{
    private static readonly DateTimeOffset Now = new(2026, 7, 6, 10, 0, 0, TimeSpan.Zero);

    [Fact]
    public async Task Payable_balance_equals_the_signed_nurse_payable_ledger_sum()
    {
        using var host = new PaymentsTestHost();
        var variantId = host.AddVariant(sessionCount: 1, price: 23_300_000);
        var requestId = host.AddAcceptedRequest(variantId);

        var initiate = new InitiatePaymentCommandHandler(host.AsCustomer(), host.UnitOfWork, host.PaymentProvider, host.Clock(Now));
        var init = await initiate.Handle(new InitiatePaymentCommand(requestId, null), CancellationToken.None);

        var confirm = new ConfirmPaymentAndPostLedgerCommandHandler(
            host.UnitOfWork, host.Config(), host.Clock(Now), host.PaymentProvider, host.Settlement, host.Serializer, host.Notifications(), TestSenders.WithTicketHooks());
        await confirm.Handle(new ConfirmPaymentAndPostLedgerCommand(init.Result.TransactionId), CancellationToken.None);

        var query = new GetNursePayableBalanceQueryHandler(host.AsNurse(), host.UnitOfWork);
        var result = await query.Handle(new GetNursePayableBalanceQuery(host.NurseId), CancellationToken.None);

        Assert.True(result.IsSuccess);
        Assert.Equal("19805000", result.Result.BalanceIrr);

        // A debit (e.g. a later payout) reduces the derived balance — never a stored column.
        host.Db.Set<LedgerEntry>().Add(new LedgerEntry
        {
            TransactionGroupId = Guid.NewGuid(), AccountType = LedgerAccountType.NursePayable, NurseId = host.NurseId,
            Direction = LedgerDirection.Debit, AmountIrr = 5_000_000, SourceRefType = LedgerSourceRefType.NursePayout,
            SourceRefId = 1, CreatedAt = Now.UtcDateTime
        });
        host.Db.SaveChanges();

        var after = await query.Handle(new GetNursePayableBalanceQuery(host.NurseId), CancellationToken.None);
        Assert.Equal((19_805_000 - 5_000_000).ToString(CultureInfo.InvariantCulture), after.Result.BalanceIrr);
    }

    [Fact]
    public async Task Non_owner_nurse_is_forbidden()
    {
        using var host = new PaymentsTestHost();
        var query = new GetNursePayableBalanceQueryHandler(host.AsCustomer(), host.UnitOfWork); // a customer, not the nurse
        var result = await query.Handle(new GetNursePayableBalanceQuery(host.NurseId), CancellationToken.None);
        Assert.True(result.IsForbidden);
    }
}
