#nullable enable
using Baya.Domain.Common;

namespace Baya.Domain.Entities.Messaging;

/// <summary>
/// A user on a ticket thread. Participation (plus admin) is the authorization boundary: only an <b>active</b>
/// participant (or an admin) may read or post. <c>UNIQUE(ticket_id, user_id)</c> is the authoritative backstop
/// against adding a user twice — a duplicate add is a clean <c>OperationResult</c> conflict, never a raw DB
/// exception. Removal is a soft <see cref="RemovedAt"/> stamp (so the unique row survives and a later re-add
/// resurrects it) rather than a hard delete.
/// </summary>
public class TicketParticipant : BaseEntity<long>
{
    public long TicketId { get; set; }
    public Ticket Ticket { get; set; } = null!;

    public int UserId { get; set; }

    /// <summary>A <see cref="TicketParticipantRole"/> label (derived), nullable.</summary>
    public string? RoleOnTicket { get; set; }

    public int? AddedById { get; set; }

    /// <summary>When this participant last read the thread — drives the inbox unread count (messages after it,
    /// internal excluded). Stamped when the participant fetches the thread. Null = never read.</summary>
    public DateTimeOffset? LastReadAt { get; private set; }

    /// <summary>Soft-remove stamp. <c>null</c> = an active participant; non-null = detached from the thread.</summary>
    public DateTimeOffset? RemovedAt { get; private set; }

    public bool IsActive => RemovedAt is null;

    public void Remove(DateTimeOffset now) => RemovedAt = now;

    public void MarkRead(DateTimeOffset now) => LastReadAt = now;

    /// <summary>Re-attaches a previously-removed participant (the same UNIQUE row), clearing the removal stamp.</summary>
    public void Restore(int? addedById)
    {
        RemovedAt = null;
        AddedById = addedById;
    }
}
