namespace Baya.Domain.Entities.Booking;

/// <summary>
/// Pure integer-money helpers for the booking split. All money is IRR <c>long</c> — no float survives into
/// storage. Kept here (not in a handler) so the reconciliation rules are unit-testable in isolation.
/// </summary>
public static class BookingAmounts
{
    /// <summary>
    /// Splits <paramref name="gross"/> into the platform commission and the derived nurse payout using the
    /// snapshotted <paramref name="rate"/>. Commission is integer-rounded (half away from zero) and clamped
    /// to <c>[0, gross]</c> so the invariant <c>gross = commission + payout</c> with all ≥ 0 always holds.
    /// </summary>
    public static (long Commission, long Payout) Split(long gross, decimal rate)
    {
        var commission = (long)decimal.Round(gross * rate, MidpointRounding.AwayFromZero);
        if (commission < 0)
            commission = 0;
        if (commission > gross)
            commission = gross;

        return (commission, gross - commission);
    }

    /// <summary>
    /// Distributes <paramref name="payout"/> across <paramref name="sessionCount"/> sessions so the parts
    /// sum <b>exactly</b> to <paramref name="payout"/> — equal integer shares with the remainder placed on
    /// the last session, so no Rial is created or lost.
    /// </summary>
    public static long[] SplitPayout(long payout, int sessionCount)
    {
        if (sessionCount < 1)
            throw new ArgumentOutOfRangeException(nameof(sessionCount), "A booking always has at least one session.");

        var per = payout / sessionCount;
        var amounts = new long[sessionCount];
        for (var i = 0; i < sessionCount; i++)
            amounts[i] = per;

        // Remainder of the integer division lands on the last session so Σ == payout exactly.
        amounts[sessionCount - 1] += payout - per * sessionCount;
        return amounts;
    }
}
