#nullable enable
using Baya.Domain.Common;

namespace Baya.Domain.Entities.Messaging;

/// <summary>
/// The root of <b>all</b> post-booking communication. There is deliberately no live chat and no direct
/// nurse↔customer side-channel: nurse and customer coordinate here, under full admin visibility, and admin-only
/// <c>is_internal</c> notes (on <see cref="TicketMessage"/>) never leak to users. A ticket optionally links a
/// <see cref="BookingId"/> and/or a <see cref="RefundId"/> — <b>both nullable</b>: a pure support ticket has
/// neither. <see cref="ReferenceCode"/> is the human-facing support id: minted once (collision-checked, UNIQUE
/// index backstop) and never mutated. Status transitions go through <see cref="Close"/>/<see cref="Reopen"/>.
/// </summary>
public class Ticket : BaseEntity<long>
{
    /// <summary>Human-facing support id (e.g. <c>TKT-3F9K2A</c>). Minted once, UNIQUE, stable, quoted to users.</summary>
    public string ReferenceCode { get; set; } = string.Empty;

    public string? Subject { get; set; }

    /// <summary>Guarded — mutated only through <see cref="Close"/>/<see cref="Reopen"/>. Defaults to
    /// <see cref="TicketStatus.Open"/>.</summary>
    public string Status { get; private set; } = TicketStatus.Open;

    /// <summary>A <see cref="TicketCategory"/> code.</summary>
    public string Category { get; set; } = TicketCategory.Support;

    /// <summary>Optional link to the booking this ticket coordinates/anchors. NULL for a pure support ticket.</summary>
    public long? BookingId { get; set; }

    /// <summary>Optional link to the refund this ticket anchors (b11's dispute paper trail). NULL otherwise.</summary>
    public long? RefundId { get; set; }

    /// <summary>The <c>users.id</c> that opened the ticket (first participant).</summary>
    public int OpenedById { get; set; }

    public DateTimeOffset? ClosedAt { get; private set; }

    public int? ClosedById { get; private set; }

    public DateTimeOffset? DeletedAt { get; set; }

    public ICollection<TicketParticipant> Participants { get; set; } = new List<TicketParticipant>();
    public ICollection<TicketMessage> Messages { get; set; } = new List<TicketMessage>();

    public bool IsOpen => Status == TicketStatus.Open;

    /// <summary>Closes the thread and stamps who/when — the owner trail also comes from the audit fields.</summary>
    public void Close(int closedById, DateTimeOffset now)
    {
        Status = TicketStatus.Closed;
        ClosedAt = now;
        ClosedById = closedById;
    }

    /// <summary>Reopens a closed thread, clearing the close stamp.</summary>
    public void Reopen()
    {
        Status = TicketStatus.Open;
        ClosedAt = null;
        ClosedById = null;
    }
}
