#nullable enable
using Baya.Domain.Common;

namespace Baya.Domain.Entities.Booking;

/// <summary>
/// One <b>visit</b> within a booking — always ≥ 1 per booking, even for a single-visit engagement, so the
/// EVV/payout path is uniform. Each session is independently scheduled, EVV-verified, and payout-accrued.
/// <para>
/// The sum of every session's <see cref="VisitPayoutAmount"/> exactly equals the booking's
/// <c>nurse_payout_amount</c> (integer split, remainder on the last session — no Rial created or lost).
/// <see cref="PayoutEligibleAt"/> is set on completion and is the per-session payout gate consumed by b13.
/// </para>
/// </summary>
public class BookingSession : BaseEntity<long>
{
    public long BookingId { get; set; }
    public Booking Booking { get; set; } = null!;

    /// <summary>1-based ordinal within the booking.</summary>
    public int SessionIndex { get; set; }

    public DateOnly ScheduledDate { get; set; }
    public TimeOnly ScheduledTimeStart { get; set; }
    public TimeOnly ScheduledTimeEnd { get; set; }

    /// <summary>This session's portion of the booking's <c>nurse_payout_amount</c> (IRR).</summary>
    public long VisitPayoutAmount { get; set; }

    /// <summary>Guarded — mutated only through <see cref="TransitionTo"/>.</summary>
    public string Status { get; private set; } = BookingSessionStatus.Scheduled;

    /// <summary>Per-session dispute-window close, set on completion. The per-session payout gate (b13).</summary>
    public DateTime? PayoutEligibleAt { get; private set; }

    /// <summary>Set when this session is cancelled — references the cancellation snapshot. The typed
    /// cancellation-event/refund record arrives in b11; nullable and unset here.</summary>
    public long? CancellationEventId { get; set; }

    public DateTimeOffset? DeletedAt { get; set; }

    public VisitVerification? Verification { get; set; }

    public bool CanTransitionTo(string target) => BookingSessionTransitions.CanTransition(Status, target);

    public void TransitionTo(string target)
    {
        if (!BookingSessionTransitions.CanTransition(Status, target))
            throw new InvalidOperationException($"Illegal booking-session transition {Status} → {target}.");

        Status = target;
    }

    public void SetPayoutEligible(DateTime at) => PayoutEligibleAt = at;
}
