using adas_core.Domain.Enums;

namespace adas_core.Domain.Models.GroupedObservations;

/// <summary>
/// Represents a field that belongs to a logical grouping, encapsulating the concept of a field within a grouped structure.
/// </summary>
/// <remarks>
/// This type is intended to model fields that are organized together as part of a group, allowing related field metadata or behavior to be handled collectively.
/// </remarks>
/// <!-- aidoc:v1 sig=57187d4 -->
public class GroupedField
{
    /// <summary>
    /// Initializes a new default instance of the <see cref="GroupedField"/> class, representing a field that aggregates related items into a single addressable group.
    /// </summary>
    /// <!-- aidoc:v1 sig=703c28d body=4448e1d -->
    public GroupedField()
    {
    }

    /// <summary>
    /// Initializes a new instance of <see cref="GroupedField"/>, which represents a configurable field for grouped observations with identifiers, scheduling offsets, and result selection.
    /// Null collection parameters are normalized to empty lists, and <paramref name="result"/> defaults to a list containing <see cref="GroupedObservationEnum.Result.First"/> when omitted.
    /// </summary>
    /// <param name="name">The primary identifier of the field, or null when only the <paramref name="names"/> collection is used.</param>
    /// <param name="names">The alternative identifiers for the field; when null, an empty <see cref="List{String}"/> is stored.</param>
    /// <param name="group">The grouping key that associates the field with a logical group, or null if unspecified.</param>
    /// <param name="startTimeShift">The list of schedule offsets applied to the field; when null, an empty <see cref="List{String}"/> is stored.</param>
    /// <param name="max">The maximum number of observations retained for the field.</param>
    /// <param name="regularity">The optional <see cref="GroupedObservationEnum.Regularity"/> that governs how observations are spaced.</param>
    /// <param name="since">The <see cref="GroupedObservationEnum.Since"/> value that defines the schedule's starting reference.</param>
    /// <param name="result">The list of <see cref="GroupedObservationEnum.Result"/> values the field should produce; when null, a list containing <see cref="GroupedObservationEnum.Result.First"/> is stored.</param>
    /// <param name="labelList">The labels associated with the field, or null when no labels are provided.</param>
    /// <!-- aidoc:v1 sig=8ca95e4 body=4742386 -->
    public GroupedField(
        string? name,
        List<string>? names,
        string? group,
        List<string>? startTimeShift,
        int max,
        GroupedObservationEnum.Regularity? regularity,
        GroupedObservationEnum.Since since,
        List<GroupedObservationEnum.Result>? result,
        List<string>? labelList)
    {
        Name = name;
        Names = names ?? [];
        Group = group;
        StartTimeShift = startTimeShift ?? [];
        Max = max;
        Regularity = regularity;
        Since = since;
        Result = result ?? [GroupedObservationEnum.Result.First];
        LabelList = labelList;
    }

    public string? Name { get; init; }

    public List<string> Names { get; init; } = [];

    public string? Group { get; init; }

    public List<string> StartTimeShift { get; init; } = [];

    public int Max { get; init; }

    public GroupedObservationEnum.Regularity? Regularity { get; init; }

    public GroupedObservationEnum.Since Since { get; init; }

    public List<GroupedObservationEnum.Result> Result { get; init; } = [];

    public List<string>? LabelList { get; init; }

    /// <summary>
    /// Retrieves the list of names stored in the current instance.
    /// </summary>
    /// <returns>A <see cref="List{String}"/> containing the names; returns the underlying field directly without copying or filtering.</returns>
    /// <!-- aidoc:v1 sig=0adca4a body=371ba0c -->
    public List<string> GetNames()
        {
            return Names;
        }

    /// <summary>
    /// Determines whether the specified object is equal to the current <see cref="GroupedField"/> by comparing their <c>Group</c> property values.
    /// Returns <c>true</c> only when <paramref name="obj"/> is a <see cref="GroupedField"/> instance with a matching <c>Group</c>; otherwise returns <c>false</c> (including for <c>null</c> or non-matching types).
    /// </summary>
    /// <param name="obj">The object to compare with the current instance.</param>
    /// <returns><c>true</c> if the specified object is a <see cref="GroupedField"/> with the same <c>Group</c>; otherwise, <c>false</c>.</returns>
    /// <!-- aidoc:v1 sig=dfd98b0 body=aa039d5 -->
    public override bool Equals(object? obj)
        {
            return obj is GroupedField field && Group == field.Group;
        }

    /// <summary>
    /// Computes a hash code for the current instance by combining the values of its key properties: Name, Group, Max, Regularity, and Result.
    /// This override ensures consistent hash-based behavior for equality comparisons and use in hash-based collections.
    /// </summary>
    /// <returns>An integer hash code derived from the object's key properties.</returns>
    /// <!-- aidoc:v1 sig=eb26c4a body=fe3f69e -->
    public override int GetHashCode()
        {
            return HashCode.Combine(Name, Group, Max, Regularity, Result);
        }
}