package common

import (
	"math"

	"github.com/tidbcloud/cluster-service-ng/pkg/autoscale/framework"
)

// TiKVUsageSnapshot is an alias for the framework type, kept for backward compatibility.
type TiKVUsageSnapshot = framework.TiKVUsageSnapshot

// ComputeRequiredDataBytes computes the required_data_bytes value that will
// cause calScaleDecisionTo() to yield currentNodeCount + additionalNodes.
//
// Formula: required_data_bytes = ((currentNodeCount + n) × nodeCapacity) × threshold/100 - currentUsage
//
// The threshold is the DefaultTiKVUsagePercentageThreshold (typically 70).
// This does NOT multiply by replica factor (DEC-015).
func ComputeRequiredDataBytes(snapshot *TiKVUsageSnapshot, additionalNodes, thresholdPercent uint32) uint64 {
	if snapshot == nil || snapshot.NodeCount == 0 || thresholdPercent == 0 || thresholdPercent >= 100 {
		return 0
	}

	nodeCapacity := snapshot.SingleNodeCapacityBytes()
	targetNodeCount := uint64(snapshot.NodeCount) + uint64(additionalNodes)
	currentUsage := snapshot.CurrentUsageBytes()

	// required_data_bytes = ((currentNodeCount + n) × nodeCapacity) × threshold/100 - currentUsage
	targetCapacityAtThreshold := uint64(math.Floor(float64(targetNodeCount*nodeCapacity) * float64(thresholdPercent) / 100))

	if targetCapacityAtThreshold <= currentUsage {
		return 0
	}
	return targetCapacityAtThreshold - currentUsage
}

// VerifyRequiredDataBytesYieldsTargetNodes verifies that the computed
// required_data_bytes would cause calScaleDecisionTo to yield the expected
// target node count. This is a sanity check function for testing.
//
// It reimplements the calScaleDecisionTo logic:
// expectedNodeCount = ceil(totalUsageAfterFulfilled / singleNodeCapacity / (threshold/100))
func VerifyRequiredDataBytesYieldsTargetNodes(
	snapshot *TiKVUsageSnapshot,
	requiredDataBytes uint64,
	thresholdPercent uint32,
	expectedNodeCount uint32,
) bool {
	if snapshot == nil || snapshot.NodeCount == 0 || thresholdPercent == 0 {
		return false
	}
	totalUsage := snapshot.CurrentUsageBytes() + requiredDataBytes
	nodeCapacity := snapshot.SingleNodeCapacityBytes()
	if nodeCapacity == 0 {
		return false
	}
	computed := math.Ceil(float64(totalUsage) / float64(nodeCapacity) / (float64(thresholdPercent) / 100.0))
	return uint32(computed) == expectedNodeCount
}
