/*
 * SPDX-FileCopyrightText: © 2017-2025 Istari Digital, Inc.
 * SPDX-License-Identifier: Apache-2.0
 */

package badger

import (
	
	
)

// PrintHistogram builds and displays the key-value size histogram.
// When keyPrefix is set, only the keys that have prefix "keyPrefix" are
// considered for creating the histogram
func ( *DB) ( []byte) {
	if  == nil {
		fmt.Println("\nCannot build histogram: DB is nil.")
		return
	}
	 := .buildHistogram()
	fmt.Printf("Histogram of key sizes (in bytes)\n")
	.keySizeHistogram.printHistogram()
	fmt.Printf("Histogram of value sizes (in bytes)\n")
	.valueSizeHistogram.printHistogram()
}

// histogramData stores information about a histogram
type histogramData struct {
	bins        []int64
	countPerBin []int64
	totalCount  int64
	min         int64
	max         int64
	sum         int64
}

// sizeHistogram contains keySize histogram and valueSize histogram
type sizeHistogram struct {
	keySizeHistogram, valueSizeHistogram histogramData
}

// newSizeHistogram returns a new instance of keyValueSizeHistogram with
// properly initialized fields.
func newSizeHistogram() *sizeHistogram {
	// TODO(ibrahim): find appropriate bin size.
	 := createHistogramBins(1, 16)
	 := createHistogramBins(1, 30)
	return &sizeHistogram{
		keySizeHistogram: histogramData{
			bins:        ,
			countPerBin: make([]int64, len()+1),
			max:         math.MinInt64,
			min:         math.MaxInt64,
			sum:         0,
		},
		valueSizeHistogram: histogramData{
			bins:        ,
			countPerBin: make([]int64, len()+1),
			max:         math.MinInt64,
			min:         math.MaxInt64,
			sum:         0,
		},
	}
}

// createHistogramBins creates bins for an histogram. The bin sizes are powers
// of two of the form [2^min_exponent, ..., 2^max_exponent].
func createHistogramBins(,  uint32) []int64 {
	var  []int64
	for  := ;  <= ; ++ {
		 = append(, int64(1)<<)
	}
	return 
}

// Update the min and max fields if value is less than or greater than the
// current min/max value.
func ( *histogramData) ( int64) {
	if  > .max {
		.max = 
	}
	if  < .min {
		.min = 
	}

	.sum += 
	.totalCount++

	for  := 0;  <= len(.bins); ++ {
		// Allocate value in the last buckets if we reached the end of the Bounds array.
		if  == len(.bins) {
			.countPerBin[]++
			break
		}

		// Check if the value should be added to the "index" bin
		if  < .bins[] {
			.countPerBin[]++
			break
		}
	}
}

// buildHistogram builds the key-value size histogram.
// When keyPrefix is set, only the keys that have prefix "keyPrefix" are
// considered for creating the histogram
func ( *DB) ( []byte) *sizeHistogram {
	 := .NewTransaction(false)
	defer .Discard()

	 := .NewIterator(DefaultIteratorOptions)
	defer .Close()

	 := newSizeHistogram()

	// Collect key and value sizes.
	for .Seek(); .ValidForPrefix(); .Next() {
		 := .Item()
		.keySizeHistogram.Update(.KeySize())
		.valueSizeHistogram.Update(.ValueSize())
	}
	return 
}

// printHistogram prints the histogram data in a human-readable format.
func ( histogramData) () {
	fmt.Printf("Total count: %d\n", .totalCount)
	fmt.Printf("Min value: %d\n", .min)
	fmt.Printf("Max value: %d\n", .max)
	fmt.Printf("Mean: %.2f\n", float64(.sum)/float64(.totalCount))
	fmt.Printf("%24s %9s\n", "Range", "Count")

	 := len(.bins)
	for ,  := range .countPerBin {
		if  == 0 {
			continue
		}

		// The last bin represents the bin that contains the range from
		// the last bin up to infinity so it's processed differently than the
		// other bins.
		if  == len(.countPerBin)-1 {
			 := int(.bins[-1])
			fmt.Printf("[%10d, %10s) %9d\n", , "infinity", )
			continue
		}

		 := int(.bins[])
		 := 0
		if  > 0 {
			 = int(.bins[-1])
		}

		fmt.Printf("[%10d, %10d) %9d\n", , , )
	}
	fmt.Println()
}