package influxdb

import (
	"math/rand"

	"github.com/influxdb/influxdb/meta"
)

// Balancer represents a load-balancing algorithm for a set of nodes
type Balancer interface {
	// Next returns the next Node according to the balancing method
	// or nil if there are no nodes available
	Next() *meta.NodeInfo
}

type nodeBalancer struct {
	nodes []meta.NodeInfo // data nodes to balance between
	p     int             // current node index
}

// NewNodeBalancer create a shuffled, round-robin balancer so that
// multiple instances will return nodes in randomized order and each
// each returned node will be repeated in a cycle
func NewNodeBalancer(nodes []meta.NodeInfo) Balancer {
	// make a copy of the node slice so we can randomize it
	// without affecting the original instance as well as ensure
	// that each Balancer returns nodes in a different order
	b := &nodeBalancer{}

	b.nodes = make([]meta.NodeInfo, len(nodes))
	copy(b.nodes, nodes)

	b.shuffle()
	return b
}

// shuffle randomizes the ordering the balancers available nodes
func (b *nodeBalancer) shuffle() {
	for i := range b.nodes {
		j := rand.Intn(i + 1)
		b.nodes[i], b.nodes[j] = b.nodes[j], b.nodes[i]
	}
}

// online returns a slice of the nodes that are online
func (b *nodeBalancer) online() []meta.NodeInfo {
	return b.nodes
	// now := time.Now().UTC()
	// up := []meta.NodeInfo{}
	// for _, n := range b.nodes {
	// 	if n.OfflineUntil.After(now) {
	// 		continue
	// 	}
	// 	up = append(up, n)
	// }
	// return up
}

// Next returns the next available nodes
func (b *nodeBalancer) Next() *meta.NodeInfo {
	// only use online nodes
	up := b.online()

	// no nodes online
	if len(up) == 0 {
		return nil
	}

	// rollover back to the beginning
	if b.p >= len(up) {
		b.p = 0
	}

	d := &up[b.p]
	b.p += 1

	return d
}