package podautoscaler

import (
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	corev1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/resource"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	metricsapi "k8s.io/metrics/pkg/apis/metrics/v1beta1"
	"sigs.k8s.io/controller-runtime/pkg/client"
)

func TestGetPodMetrics(t *testing.T) {
	timestamp := time.Now()
	window := 1 * time.Minute

	tests := []struct {
		name         string
		rawMetrics   []metricsapi.PodMetrics
		resourceName corev1.ResourceName
		expected     PodMetricsInfo
	}{
		{
			name:         "empty metrics",
			rawMetrics:   []metricsapi.PodMetrics{},
			resourceName: corev1.ResourceCPU,
			expected:     PodMetricsInfo{},
		},
		{
			name: "single pod single container cpu",
			rawMetrics: []metricsapi.PodMetrics{
				{
					ObjectMeta: metav1.ObjectMeta{Name: "pod1", Namespace: "ns1"},
					Timestamp:  metav1.Time{Time: timestamp},
					Window:     metav1.Duration{Duration: window},
					Containers: []metricsapi.ContainerMetrics{
						{
							Name: "container1",
							Usage: corev1.ResourceList{
								corev1.ResourceCPU: *resource.NewMilliQuantity(100, resource.DecimalSI),
							},
						},
					},
				},
			},
			resourceName: corev1.ResourceCPU,
			expected: PodMetricsInfo{
				client.ObjectKey{Namespace: "ns1", Name: "pod1"}: PodMetric{
					Timestamp: timestamp,
					Window:    window,
					Value:     100,
				},
			},
		},
		{
			name: "single pod multiple containers memory",
			rawMetrics: []metricsapi.PodMetrics{
				{
					ObjectMeta: metav1.ObjectMeta{Name: "pod1", Namespace: "ns1"},
					Timestamp:  metav1.Time{Time: timestamp},
					Window:     metav1.Duration{Duration: window},
					Containers: []metricsapi.ContainerMetrics{
						{
							Name: "container1",
							Usage: corev1.ResourceList{
								corev1.ResourceMemory: *resource.NewQuantity(1024, resource.BinarySI),
							},
						},
						{
							Name: "container2",
							Usage: corev1.ResourceList{
								corev1.ResourceMemory: *resource.NewQuantity(2048, resource.BinarySI),
							},
						},
					},
				},
			},
			resourceName: corev1.ResourceMemory,
			expected: PodMetricsInfo{
				client.ObjectKey{Namespace: "ns1", Name: "pod1"}: PodMetric{
					Timestamp: timestamp,
					Window:    window,
					Value:     3072000,
					// 1024 bytes = 1024000m.
					// 2048 bytes = 2048000m.
					// Sum = 3072000m.
				},
			},
		},
		{
			name: "multiple pods",
			rawMetrics: []metricsapi.PodMetrics{
				{
					ObjectMeta: metav1.ObjectMeta{Name: "pod1", Namespace: "ns1"},
					Timestamp:  metav1.Time{Time: timestamp},
					Window:     metav1.Duration{Duration: window},
					Containers: []metricsapi.ContainerMetrics{
						{
							Name: "c1",
							Usage: corev1.ResourceList{
								corev1.ResourceCPU: *resource.NewMilliQuantity(100, resource.DecimalSI),
							},
						},
					},
				},
				{
					ObjectMeta: metav1.ObjectMeta{Name: "pod2", Namespace: "ns1"},
					Timestamp:  metav1.Time{Time: timestamp},
					Window:     metav1.Duration{Duration: window},
					Containers: []metricsapi.ContainerMetrics{
						{
							Name: "c1",
							Usage: corev1.ResourceList{
								corev1.ResourceCPU: *resource.NewMilliQuantity(200, resource.DecimalSI),
							},
						},
					},
				},
			},
			resourceName: corev1.ResourceCPU,
			expected: PodMetricsInfo{
				client.ObjectKey{Namespace: "ns1", Name: "pod1"}: PodMetric{
					Timestamp: timestamp,
					Window:    window,
					Value:     100,
				},
				client.ObjectKey{Namespace: "ns1", Name: "pod2"}: PodMetric{
					Timestamp: timestamp,
					Window:    window,
					Value:     200,
				},
			},
		},
		{
			name: "pod with missing resource",
			rawMetrics: []metricsapi.PodMetrics{
				{
					ObjectMeta: metav1.ObjectMeta{Name: "pod1", Namespace: "ns1"},
					Containers: []metricsapi.ContainerMetrics{
						{
							Name: "c1",
							Usage: corev1.ResourceList{
								corev1.ResourceMemory: *resource.NewQuantity(100, resource.BinarySI),
							},
						},
					},
				},
			},
			resourceName: corev1.ResourceCPU,
			expected:     PodMetricsInfo{}, // Should be skipped
		},
		{
			name: "pod with no containers",
			rawMetrics: []metricsapi.PodMetrics{
				{
					ObjectMeta: metav1.ObjectMeta{Name: "pod1", Namespace: "ns1"},
					Containers: []metricsapi.ContainerMetrics{},
				},
			},
			resourceName: corev1.ResourceCPU,
			expected:     PodMetricsInfo{}, // Should be skipped
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got := getPodMetrics(tt.rawMetrics, tt.resourceName)
			assert.Equal(t, len(tt.expected), len(got))
			for k, v := range tt.expected {
				gotMetric, ok := got[k]
				assert.True(t, ok)
				assert.Equal(t, v.Timestamp, gotMetric.Timestamp)
				assert.Equal(t, v.Window, gotMetric.Window)
				assert.Equal(t, v.Value, gotMetric.Value)
			}
		})
	}
}
