package routing

import (
	"fmt"
	"net/netip"
)

const (
	// Sentinel value
	BucketNotCalculated = -1
)

type Gateways []Gateway

func (g Gateways) String() string {
	str := ""
	for i, gw := range g {
		str += gw.String()
		if i < len(g)-1 {
			str += ", "
		}
	}
	return str
}

type Gateway struct {
	addr             netip.Addr
	weight           int
	bucketUpperBound int
}

func NewGateway(addr netip.Addr, weight int) Gateway {
	return Gateway{addr: addr, weight: weight, bucketUpperBound: BucketNotCalculated}
}

func (g *Gateway) BucketUpperBound() int {
	return g.bucketUpperBound
}

func (g *Gateway) Addr() netip.Addr {
	return g.addr
}

func (g *Gateway) String() string {
	return fmt.Sprintf("{addr: %s, weight: %d}", g.addr, g.weight)
}

// Divide and round to nearest integer
func divideAndRound(v uint64, d uint64) uint64 {
	var tmp uint64 = v + d/2
	return tmp / d
}

// Implements Hash-Threshold mapping, equivalent to the implementation in the linux kernel.
// After this function returns each gateway will have a
// positive bucketUpperBound with a maximum value of 2147483647 (INT_MAX)
func CalculateBucketsForGateways(gateways []Gateway) {

	var totalWeight int = 0
	for i := range gateways {
		totalWeight += gateways[i].weight
	}

	var loopWeight int = 0
	for i := range gateways {
		loopWeight += gateways[i].weight
		gateways[i].bucketUpperBound = int(divideAndRound(uint64(loopWeight)<<31, uint64(totalWeight))) - 1
	}

}
