using System.Text.Json.Serialization;

namespace NATS.Server.JetStream.Cluster;

/// <summary>
/// RAFT group describing which peers own a replicated asset (stream or consumer).
/// Go reference: jetstream_cluster.go:154-163 raftGroup struct.
/// </summary>
public sealed class RaftGroup
{
    public required string Name { get; init; }
    public List<string> Peers { get; init; } = [];
    public string StorageType { get; set; } = "file";
    public string Cluster { get; set; } = string.Empty;
    public string Preferred { get; set; } = string.Empty;

    public int QuorumSize => (Peers.Count / 2) + 1;
    public bool HasQuorum(int ackCount) => ackCount >= QuorumSize;
}

/// <summary>
/// Assignment of a stream to a RAFT group of peers.
/// Go reference: jetstream_cluster.go:166-184 streamAssignment struct.
/// </summary>
public sealed class StreamAssignment
{
    public required string StreamName { get; init; }
    public required RaftGroup Group { get; init; }
    public DateTime Created { get; init; } = DateTime.UtcNow;
    public string ConfigJson { get; set; } = "{}";
    public string SyncSubject { get; set; } = string.Empty;
    public bool Responded { get; set; }
    public bool Recovering { get; set; }
    public bool Reassigning { get; set; }

    /// <summary>
    /// Consumer assignments keyed by consumer name.
    /// Uses <see cref="JsonObjectCreationHandling.Populate"/> so the deserializer populates
    /// the existing dictionary instance rather than replacing it (the property has no setter).
    /// </summary>
    [JsonObjectCreationHandling(JsonObjectCreationHandling.Populate)]
    public Dictionary<string, ConsumerAssignment> Consumers { get; } = new(StringComparer.Ordinal);
}

/// <summary>
/// Assignment of a consumer to a RAFT group within a stream's cluster.
/// Go reference: jetstream_cluster.go:250-266 consumerAssignment struct.
/// </summary>
public sealed class ConsumerAssignment
{
    public required string ConsumerName { get; init; }
    public required string StreamName { get; init; }
    public required RaftGroup Group { get; init; }
    public DateTime Created { get; init; } = DateTime.UtcNow;
    public string ConfigJson { get; set; } = "{}";
    public bool Responded { get; set; }
    public bool Recovering { get; set; }
}
