package partition

// Quorum models replicated reads/writes over N replicas. The key
// guarantee: if a write touches W replicas and a read touches R
// replicas, then R+W>N forces the read and write sets to OVERLAP (by
// pigeonhole), so the read is guaranteed to see the latest write
// (strong/read-your-writes consistency). When R+W<=N, the sets can be
// disjoint and a read may return a stale value (eventual consistency).

// Cluster is N replicas, each holding a version number (the value's
// recency). Higher version = more recent.
type Cluster struct {
	versions []int
}

// NewCluster creates N replicas all at version 1 (an initial value).
func NewCluster(n int) *Cluster {
	v := make([]int, n)
	for i := range v {
		v[i] = 1
	}
	return &Cluster{versions: v}
}

func (c *Cluster) N() int { return len(c.versions) }

// Write updates the first W replicas to `version` — a write that reached
// a W-quorum (the other replicas are stale until anti-entropy/read-repair
// catches them up).
func (c *Cluster) Write(w, version int) {
	if w > len(c.versions) {
		w = len(c.versions)
	}
	for i := 0; i < w; i++ {
		c.versions[i] = version
	}
}

// ReadWorstCase reads the R replicas LEAST likely to hold a recent write
// (the last R), returning the highest version seen. This is the
// adversarial case for staleness: if even this read sees the latest
// version, the quorum overlaps; if it doesn't, R+W<=N let the read miss
// the write.
func (c *Cluster) ReadWorstCase(r int) int {
	if r > len(c.versions) {
		r = len(c.versions)
	}
	max := 0
	for i := len(c.versions) - r; i < len(c.versions); i++ {
		if c.versions[i] > max {
			max = c.versions[i]
		}
	}
	return max
}

// QuorumOverlaps reports whether R+W>N (the strong-consistency condition).
func QuorumOverlaps(n, w, r int) bool { return w+r > n }
