#nullable enable
using Baya.Domain.Common;

namespace Baya.Domain.Entities.Reviews;

/// <summary>
/// One customer review of a <b>completed</b> booking (1:1 with the booking, enforced by a UNIQUE on
/// <see cref="BookingId"/>). A review is public social-proof and enters <see cref="ReviewModerationStatus.PendingModeration"/>;
/// it is never rendered publicly and never counted in the nurse aggregate until a moderation transition
/// publishes it. The moderation fields are guarded (private setters) and mutated only through
/// <see cref="Moderate"/>, so every transition also stamps the moderator and time. Marked
/// <see cref="IAuditable"/> so the SaveChanges interceptor writes an append-only <c>audit_logs</c> diff for
/// creation and every moderation transition in the same transaction.
/// </summary>
public class Review : BaseEntity<long>, IAuditable
{
    /// <summary>1:1 with the completed booking (UNIQUE) — the anti-fraud, one-review-per-booking backstop.</summary>
    public long BookingId { get; set; }

    /// <summary>The reviewing customer's <c>customer_profiles.id</c> (author).</summary>
    public long CustomerProfileId { get; set; }

    /// <summary>The reviewed nurse's <c>nurse_profiles.id</c> — the aggregate this review drives when published.</summary>
    public long NurseProfileId { get; set; }

    /// <summary>1–5, enforced by a DB CHECK and by validation.</summary>
    public int Rating { get; set; }

    /// <summary>Optional free-text body.</summary>
    public string? Body { get; set; }

    /// <summary>Guarded — mutated only through <see cref="Moderate"/>. Defaults to
    /// <see cref="ReviewModerationStatus.PendingModeration"/>; never public until published.</summary>
    public string ModerationStatus { get; private set; } = Reviews.ReviewModerationStatus.PendingModeration;

    /// <summary>Set on hide/reject.</summary>
    public string? ModerationReason { get; private set; }

    public int? ModeratedById { get; private set; }

    public DateTimeOffset? ModeratedAt { get; private set; }

    public DateTimeOffset? DeletedAt { get; set; }

    public ICollection<ReviewTagLink> TagLinks { get; set; } = new List<ReviewTagLink>();

    /// <summary>Applies a moderation transition and stamps the moderator + time. The caller maps the action
    /// to a valid target status; a hide/reject carries a reason (cleared on publish/unpublish). The moderator
    /// is null when the AI pre-screen set the initial disposition on submit.</summary>
    public void Moderate(string targetStatus, string? reason, int? moderatedById, DateTimeOffset now)
    {
        ModerationStatus = targetStatus;
        ModerationReason = reason;
        ModeratedById = moderatedById;
        ModeratedAt = now;
    }
}
