package util

import (
	"testing"
)

func TestPercentileInt64(t *testing.T) {
	tests := []struct {
		name       string
		arr        []int64
		percentile int
		expected   float64
	}{
		{
			name:       "empty array",
			arr:        []int64{},
			percentile: 50,
			expected:   0,
		},
		{
			name:       "invalid percentile - negative",
			arr:        []int64{1, 2, 3, 4, 5},
			percentile: -10,
			expected:   0,
		},
		{
			name:       "invalid percentile - over 100",
			arr:        []int64{1, 2, 3, 4, 5},
			percentile: 110,
			expected:   0,
		},
		{
			name:       "single element - 50th percentile",
			arr:        []int64{42},
			percentile: 50,
			expected:   42,
		},
		{
			name:       "single element - 0th percentile",
			arr:        []int64{42},
			percentile: 0,
			expected:   42,
		},
		{
			name:       "single element - 100th percentile",
			arr:        []int64{42},
			percentile: 100,
			expected:   42,
		},
		{
			name:       "two elements - 50th percentile",
			arr:        []int64{10, 20},
			percentile: 50,
			expected:   15,
		},
		{
			name:       "five elements - 0th percentile",
			arr:        []int64{1, 2, 3, 4, 5},
			percentile: 0,
			expected:   1,
		},
		{
			name:       "five elements - 25th percentile",
			arr:        []int64{1, 2, 3, 4, 5},
			percentile: 25,
			expected:   2,
		},
		{
			name:       "five elements - 50th percentile (median)",
			arr:        []int64{1, 2, 3, 4, 5},
			percentile: 50,
			expected:   3,
		},
		{
			name:       "five elements - 75th percentile",
			arr:        []int64{1, 2, 3, 4, 5},
			percentile: 75,
			expected:   4,
		},
		{
			name:       "five elements - 100th percentile",
			arr:        []int64{1, 2, 3, 4, 5},
			percentile: 100,
			expected:   5,
		},
		{
			name:       "unsorted array - 50th percentile",
			arr:        []int64{5, 1, 3, 2, 4},
			percentile: 50,
			expected:   3,
		},
		{
			name:       "array with duplicates - 50th percentile",
			arr:        []int64{1, 2, 2, 3, 4},
			percentile: 50,
			expected:   2,
		},
		{
			name:       "array with negative numbers - 50th percentile",
			arr:        []int64{-10, -5, 0, 5, 10},
			percentile: 50,
			expected:   0,
		},
		{
			name:       "large numbers - 90th percentile",
			arr:        []int64{1000000, 2000000, 3000000, 4000000, 5000000},
			percentile: 90,
			expected:   4600000,
		},
		{
			name:       "four elements - 33rd percentile (interpolation)",
			arr:        []int64{10, 20, 30, 40},
			percentile: 33,
			expected:   19.9, // Should interpolate between 20 and 30
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := PercentileInt64(tt.arr, tt.percentile)

			// Use a small epsilon for floating point comparison
			epsilon := 0.1
			if abs(result-tt.expected) > epsilon {
				t.Errorf("PercentileInt64(%v, %d) = %f, expected %f",
					tt.arr, tt.percentile, result, tt.expected)
			}
		})
	}
}

// Helper function for absolute value of float64
func abs(x float64) float64 {
	if x < 0 {
		return -x
	}
	return x
}

func TestPercentileInt64_DoesNotModifyOriginalArray(t *testing.T) {
	original := []int64{5, 1, 3, 2, 4}
	expected := []int64{5, 1, 3, 2, 4}

	_ = PercentileInt64(original, 50)

	// Check that original array is unchanged
	if len(original) != len(expected) {
		t.Errorf("Original array length changed")
		return
	}

	for i, v := range original {
		if v != expected[i] {
			t.Errorf("Original array was modified at index %d: got %d, expected %d",
				i, v, expected[i])
		}
	}
}
