namespace adas_core.Domain.Models;

/// <summary>
/// Represents a historical location and provides type-safe equality comparison between instances of <see cref="HistoricalLocation"/>.
/// </summary>
/// <remarks>
/// Implements <see cref="IEquatable{T}"/> of <see cref="HistoricalLocation"/> to allow instances to be compared for value equality without relying on object identity.
/// </remarks>
public class HistoricalLocation : IEquatable<HistoricalLocation>
{
    // Propiedades con get y set para que MongoDB pueda escribir en ellas
    public DateTime? AdmTime { get; set; }
    public PatientLocation? PatientLocation { get; set; }

    // Constructor vacío necesario para la deserialización de MongoDB
    /// <summary>
    /// Initializes a new instance of the <see cref="HistoricalLocation"/> class, which represents a historical record of a location.
    /// </summary>
    public HistoricalLocation() { }

    // Tu constructor actual
    public HistoricalLocation(DateTime admTime, PatientLocation patientLocation)
    {
        AdmTime = admTime;
        PatientLocation = patientLocation ?? throw new ArgumentNullException(nameof(patientLocation));
    }

    /// <summary>
    /// Determines whether the current <see cref="HistoricalLocation"/> instance is equal to another instance,
    /// based on the admission time and the patient location (when present, with null locations treated as equal).
    /// </summary>
    /// <param name="other">The other <see cref="HistoricalLocation"/> instance to compare with this one.</param>
    /// <returns><c>true</c> if both the admission time and patient location match; otherwise, <c>false</c>.</returns>
    public bool Equals(HistoricalLocation? other)
        {
            if (other == null) return false;
            return AdmTime == other.AdmTime &&
                   (PatientLocation?.Equals(other.PatientLocation) ?? other.PatientLocation == null);
        }

    /// <summary>
    /// Determines whether this instance is considered empty by verifying that no admission time is set and that the patient location is either null or empty.
    /// </summary>
    /// <returns><see langword="true"/> when <c>AdmTime</c> has no value and <c>PatientLocation</c> is <see langword="null"/> or empty; otherwise, <see langword="false"/>.</returns>
    public bool IsEmpty() => !AdmTime.HasValue && (PatientLocation == null || PatientLocation.IsEmpty());

    /// <summary>
    /// Determines whether the instance is in a full state by verifying that an admission time has been set, a patient location is assigned, and the assigned location is not full or empty.
    /// </summary>
    /// <returns><c>true</c> when <see cref="AdmTime"/> has a value, <see cref="PatientLocation"/> is not null, and the location is not full or empty; otherwise, <c>false</c>.</returns>
    public bool IsFull() => AdmTime.HasValue && PatientLocation != null && !PatientLocation.IsFullEmpty();

    /// <summary>
    /// Returns a string representation of the HistoricalLocation, including the admission time and patient location.
    /// </summary>
    /// <returns>A formatted string with the values of <c>AdmTime</c> and <c>PatientLocation</c>.</returns>
    public override string ToString() => $"HistoricalLocation[AdmTime: {AdmTime}, PatientLocation: {PatientLocation}]";
}