namespace ZB.MOM.WW.ScadaBridge.Commons.Types.Flattening;

/// <summary>
/// Represents the difference between two FlattenedConfigurations (typically deployed vs current).
/// Used for incremental deployment decisions and change review.
/// </summary>
public sealed record ConfigurationDiff
{
    /// <summary>Unique name of the instance this diff applies to.</summary>
    public string InstanceUniqueName { get; init; } = string.Empty;
    /// <summary>Revision hash of the previously deployed configuration, or null if not previously deployed.</summary>
    public string? OldRevisionHash { get; init; }
    /// <summary>Revision hash of the new configuration being compared.</summary>
    public string? NewRevisionHash { get; init; }
    /// <summary>True when any attribute, alarm, script, native alarm source, or connection changes are present.</summary>
    public bool HasChanges => AttributeChanges.Count > 0 || AlarmChanges.Count > 0 || ScriptChanges.Count > 0 || NativeAlarmSourceChanges.Count > 0 || ConnectionChanges.Count > 0;

    /// <summary>Diff entries for resolved attributes.</summary>
    public IReadOnlyList<DiffEntry<ResolvedAttribute>> AttributeChanges { get; init; } = [];
    /// <summary>Diff entries for resolved alarms.</summary>
    public IReadOnlyList<DiffEntry<ResolvedAlarm>> AlarmChanges { get; init; } = [];
    /// <summary>Diff entries for resolved scripts.</summary>
    public IReadOnlyList<DiffEntry<ResolvedScript>> ScriptChanges { get; init; } = [];

    /// <summary>
    /// Diff entries for resolved native alarm source bindings, keyed by canonical
    /// name. Surfaces native-alarm-source edits (connection, source reference,
    /// condition filter, lock state) in the Deployments diff view.
    /// </summary>
    public IReadOnlyList<DiffEntry<ResolvedNativeAlarmSource>> NativeAlarmSourceChanges { get; init; } = [];

    /// <summary>
    /// Diff entries for connection configurations, keyed by connection name.
    /// Surfaces standalone endpoint/protocol/failover drift that does not show
    /// up as a per-attribute binding change.
    /// </summary>
    public IReadOnlyList<DiffEntry<ConnectionConfig>> ConnectionChanges { get; init; } = [];
}

/// <summary>
/// A single diff entry showing what changed for a named entity.
/// </summary>
public sealed record DiffEntry<T>
{
    /// <summary>The canonical name of the changed entity.</summary>
    public string CanonicalName { get; init; } = string.Empty;
    /// <summary>The type of change: Added, Removed, or Changed.</summary>
    public DiffChangeType ChangeType { get; init; }

    /// <summary>
    /// The previous value (null for Added entries).
    /// </summary>
    public T? OldValue { get; init; }

    /// <summary>
    /// The new value (null for Removed entries).
    /// </summary>
    public T? NewValue { get; init; }
}

public enum DiffChangeType
{
    Added,
    Removed,
    Changed
}
