package gavalink

import (
	"math"
	"sort"
)

type balancePenalty struct {
	node    *Node
	penalty int
}

func BestNodeByPenalties(nodes []*Node) (*Node, error) {
	penalties := make([]balancePenalty, len(nodes))

	var playerPenalty, cpuPenalty, deficitFramePenalty, nullFramePenalty int

	for i, node := range nodes {
		playerPenalty = 0
		cpuPenalty = 0
		deficitFramePenalty = 0
		nullFramePenalty = 0

		if node.stats != nil {
			playerPenalty = node.stats.ActivePlayers
			cpuPenalty = int(math.Pow(1.05, 100*node.stats.Cpu.SystemLoad)*10 - 10)

			if node.stats.Frames != nil && node.stats.Frames.Deficit != -1 {
				deficitFramePenalty = int(math.Pow(1.03, 500*float64(node.stats.Frames.Deficit/3000))*600 - 600)
				nullFramePenalty = int(math.Pow(1.03, 500*float64(node.stats.Frames.Nulled/3000))*300 - 300)
				nullFramePenalty *= 2
			}
		}

		penalties[i] = balancePenalty{node, playerPenalty + cpuPenalty + deficitFramePenalty + nullFramePenalty}
	}

	sort.SliceStable(penalties, func(i, j int) bool {
		return penalties[i].penalty < penalties[j].penalty
	})

	return penalties[0].node, nil
}

func BestNodeByLoad(n []*Node) (*Node, error) {
	sort.SliceStable(n, func(i, j int) bool {
		return n[i].stats.Cpu.LavalinkLoad < n[j].stats.Cpu.LavalinkLoad
	})

	return n[0], nil
}