package config

import (
	"testing"

	"github.com/stretchr/testify/assert"
	"k8s.io/utils/ptr"

	"github.com/tidbcloud/infra-provider/regional-server/api/v1alpha1"
)

func TestGetAdminNodeConfig(t *testing.T) {
	defaultInstanceType := "default-instance-type"
	defaultMinSize := 2
	defaultMaxSize := 10
	defaultSystemVolumeSize := int64(20)

	tests := []struct {
		name                string
		crAdminNodeConfig   v1alpha1.NodeConfig
		configFileAdminNode AdminNodeConfig
		expected            AdminNodeConfigValues
	}{
		{
			name: "all from CR spec",
			crAdminNodeConfig: v1alpha1.NodeConfig{
				InstanceType:     "cr-instance-type",
				MinSize:          ptr.To(int32(3)),
				MaxSize:          ptr.To(int32(12)),
				SystemVolumeSize: ptr.To(int64(100)),
			},
			configFileAdminNode: AdminNodeConfig{
				InstanceType:     ptr.To("config-instance-type"),
				MinSize:          ptr.To(int32(4)),
				MaxSize:          ptr.To(int32(15)),
				SystemVolumeSize: ptr.To(int64(80)),
			},
			expected: AdminNodeConfigValues{
				InstanceType:     "cr-instance-type",
				MinSize:          3,
				MaxSize:          12,
				SystemVolumeSize: 100,
			},
		},
		{
			name:              "all from config file",
			crAdminNodeConfig: v1alpha1.NodeConfig{},
			configFileAdminNode: AdminNodeConfig{
				InstanceType:     ptr.To("config-instance-type"),
				MinSize:          ptr.To(int32(4)),
				MaxSize:          ptr.To(int32(15)),
				SystemVolumeSize: ptr.To(int64(80)),
			},
			expected: AdminNodeConfigValues{
				InstanceType:     "config-instance-type",
				MinSize:          4,
				MaxSize:          15,
				SystemVolumeSize: 80,
			},
		},
		{
			name:                "all from defaults",
			crAdminNodeConfig:   v1alpha1.NodeConfig{},
			configFileAdminNode: AdminNodeConfig{},
			expected: AdminNodeConfigValues{
				InstanceType:     defaultInstanceType,
				MinSize:          defaultMinSize,
				MaxSize:          defaultMaxSize,
				SystemVolumeSize: defaultSystemVolumeSize,
			},
		},
		{
			name: "mixed sources: instance from CR, sizes from config",
			crAdminNodeConfig: v1alpha1.NodeConfig{
				InstanceType: "cr-instance-type",
			},
			configFileAdminNode: AdminNodeConfig{
				MinSize:          ptr.To(int32(5)),
				MaxSize:          ptr.To(int32(20)),
				SystemVolumeSize: ptr.To(int64(120)),
			},
			expected: AdminNodeConfigValues{
				InstanceType:     "cr-instance-type",
				MinSize:          5,
				MaxSize:          20,
				SystemVolumeSize: 120,
			},
		},
		{
			name: "mixed sources: sizes from CR, instance from config",
			crAdminNodeConfig: v1alpha1.NodeConfig{
				MinSize:          ptr.To(int32(3)),
				MaxSize:          ptr.To(int32(8)),
				SystemVolumeSize: ptr.To(int64(60)),
			},
			configFileAdminNode: AdminNodeConfig{
				InstanceType: ptr.To("config-instance-type"),
			},
			expected: AdminNodeConfigValues{
				InstanceType:     "config-instance-type",
				MinSize:          3,
				MaxSize:          8,
				SystemVolumeSize: 60,
			},
		},
		{
			name: "empty string in CR falls back to config",
			crAdminNodeConfig: v1alpha1.NodeConfig{
				InstanceType: "",
			},
			configFileAdminNode: AdminNodeConfig{
				InstanceType: ptr.To("config-instance-type"),
			},
			expected: AdminNodeConfigValues{
				InstanceType:     "config-instance-type",
				MinSize:          defaultMinSize,
				MaxSize:          defaultMaxSize,
				SystemVolumeSize: defaultSystemVolumeSize,
			},
		},
		{
			name:              "additional instance types from config file",
			crAdminNodeConfig: v1alpha1.NodeConfig{},
			configFileAdminNode: AdminNodeConfig{
				InstanceType:            ptr.To("config-instance-type"),
				AdditionalInstanceTypes: []string{"extra-type-1", "extra-type-2"},
			},
			expected: AdminNodeConfigValues{
				InstanceType:            "config-instance-type",
				MinSize:                 defaultMinSize,
				MaxSize:                 defaultMaxSize,
				SystemVolumeSize:        defaultSystemVolumeSize,
				AdditionalInstanceTypes: []string{"extra-type-1", "extra-type-2"},
			},
		},
		{
			name: "additional instance types from CR overrides config file",
			crAdminNodeConfig: v1alpha1.NodeConfig{
				AdditionalInstanceTypes: []string{"cr-type-1", "cr-type-2"},
			},
			configFileAdminNode: AdminNodeConfig{
				AdditionalInstanceTypes: []string{"config-type-1"},
			},
			expected: AdminNodeConfigValues{
				InstanceType:            defaultInstanceType,
				MinSize:                 defaultMinSize,
				MaxSize:                 defaultMaxSize,
				SystemVolumeSize:        defaultSystemVolumeSize,
				AdditionalInstanceTypes: []string{"cr-type-1", "cr-type-2"},
			},
		},
		{
			name: "empty CR additional instance types falls back to config file",
			crAdminNodeConfig: v1alpha1.NodeConfig{
				AdditionalInstanceTypes: nil,
			},
			configFileAdminNode: AdminNodeConfig{
				AdditionalInstanceTypes: []string{"config-type-1"},
			},
			expected: AdminNodeConfigValues{
				InstanceType:            defaultInstanceType,
				MinSize:                 defaultMinSize,
				MaxSize:                 defaultMaxSize,
				SystemVolumeSize:        defaultSystemVolumeSize,
				AdditionalInstanceTypes: []string{"config-type-1"},
			},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := GetAdminNodeConfig(
				tt.crAdminNodeConfig,
				tt.configFileAdminNode,
				defaultInstanceType,
				defaultMinSize,
				defaultMaxSize,
				defaultSystemVolumeSize,
			)
			assert.Equal(t, tt.expected, result)
		})
	}
}
