package weightDistributing

import (
	"errors"
	"math"
)

type Weight struct {
	Id      string
	Weight  int32
	Replica int32
}

func DistributeReplicas(weights []*Weight, replicas int32) error {

	var weightSum int32
	weightSum = 0
	for _, w := range weights {
		weightSum += w.Weight
	}

	if weightSum == 0 {
		return errors.New("static weights are empty")
	}

	weightRatio := make([]float64, len(weights))
	for i, w := range weights {
		weightRatio[i] = float64(w.Weight) / float64(weightSum)
	}

	var rest = replicas

	for i := 0; i < len(weights); i++ {

		var n = math.Round(float64(replicas) * weightRatio[i])
		rest -= int32(n)

		weights[i].Replica = int32(n)
	}

	for {
		if rest == 0 {
			break
		}

		maxIdx := 0
		minIdx := 0

		if rest > 0 {
			for i, ratio := range weightRatio {
				if ratio > weightRatio[maxIdx] {
					maxIdx = i
				}
			}
		} else {
			for i, ratio := range weightRatio {
				if ratio < weightRatio[minIdx] {
					minIdx = i
				}
			}
		}

		if rest > 0 {
			weights[maxIdx].Replica++
			weightRatio[maxIdx]--
			rest--
		} else {
			if weights[minIdx].Replica == 0 {
				weightRatio[minIdx]++
				continue
			}
			weights[minIdx].Replica--
			weightRatio[minIdx]++
			rest++
		}
	}
	return nil
}
