package nodegroup

import (
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func TestValidateSpec(t *testing.T) {
	tests := []struct {
		name    string
		spec    string
		wantErr bool
	}{
		{"valid lowercase", "8c16g", false},
		{"valid uppercase", "8C16G", false},
		{"valid mixed", "16c32G", false},
		{"valid large", "128c256g", false},
		{"empty", "", true},
		{"invalid format - missing c", "816g", true},
		{"invalid format - missing g", "8c16", true},
		{"invalid format - letters", "abc", true},
		{"invalid format - special chars", "8c-16g", true},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			err := ValidateSpec(tt.spec)
			if tt.wantErr {
				assert.Error(t, err)
			} else {
				assert.NoError(t, err)
			}
		})
	}
}

func TestValidateCloudInstanceType(t *testing.T) {
	tests := []struct {
		name         string
		instanceType string
		wantErr      bool
	}{
		{"valid AWS m5", "m5.2xlarge", false},
		{"valid AWS m5a", "m5a.4xlarge", false},
		{"valid AWS r6g", "r6g.xlarge", false},
		{"valid GCP n2", "n2.standard8", false},
		{"valid GCP n2-standard-8", "n2-standard-8", false},
		{"valid Azure Standard_D8s_v3", "Standard_D8s_v3", false},
		{"empty", "", true},
		{"invalid - starts with number", "5m.2xlarge", true},
		{"invalid - single word", "invalid", true},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			err := ValidateCloudInstanceType(tt.instanceType)
			if tt.wantErr {
				assert.Error(t, err)
			} else {
				assert.NoError(t, err)
			}
		})
	}
}

func TestValidateAvailableCPU(t *testing.T) {
	tests := []struct {
		name    string
		cpu     string
		wantErr bool
	}{
		{"valid 7", "7", false},
		{"valid 128", "128", false},
		{"valid 256", "256", false},
		{"invalid 0", "0", true},
		{"invalid negative", "-1", true},
		{"invalid too large", "257", true},
		{"invalid not number", "abc", true},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			err := ValidateAvailableCPU(tt.cpu)
			if tt.wantErr {
				assert.Error(t, err)
			} else {
				assert.NoError(t, err)
			}
		})
	}
}

func TestValidateAvailableMemoryMi(t *testing.T) {
	tests := []struct {
		name    string
		memory  string
		wantErr bool
	}{
		{"valid 15360 (15 GiB)", "15360", false},
		{"valid 524288 (512 GiB)", "524288", false},
		{"valid 2097152 (2 TiB)", "2097152", false},
		{"invalid 0", "0", true},
		{"invalid negative", "-1", true},
		{"invalid too large", "2097153", true},
		{"invalid not number", "abc", true},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			err := ValidateAvailableMemoryMi(tt.memory)
			if tt.wantErr {
				assert.Error(t, err)
			} else {
				assert.NoError(t, err)
			}
		})
	}
}

func TestValidateSharedPoolID(t *testing.T) {
	tests := []struct {
		name    string
		id      string
		wantErr bool
	}{
		{"valid short", "sp-1", false},
		{"valid uuid-like", "sp-12345678-abcd-1234-efgh-123456789012", false},
		{"empty", "", true},
		{"too short", "sp", true},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			err := ValidateSharedPoolID(tt.id)
			if tt.wantErr {
				assert.Error(t, err)
			} else {
				assert.NoError(t, err)
			}
		})
	}
}

func TestValidateInstanceTypeSpec(t *testing.T) {
	tests := []struct {
		name    string
		spec    InstanceTypeSpec
		wantErr bool
	}{
		{
			name: "valid full spec",
			spec: InstanceTypeSpec{
				Spec:              "8c16g",
				InstanceType:      "m5.2xlarge",
				AvailableCPU:      "7",
				AvailableMemoryMi: "15360",
			},
			wantErr: false,
		},
		{
			name: "valid without optional fields",
			spec: InstanceTypeSpec{
				Spec:         "8c16g",
				InstanceType: "m5.2xlarge",
			},
			wantErr: false,
		},
		{
			name: "invalid spec",
			spec: InstanceTypeSpec{
				Spec:         "invalid",
				InstanceType: "m5.2xlarge",
			},
			wantErr: true,
		},
		{
			name: "invalid instance type",
			spec: InstanceTypeSpec{
				Spec:         "8c16g",
				InstanceType: "invalid",
			},
			wantErr: true,
		},
		{
			name: "invalid available cpu",
			spec: InstanceTypeSpec{
				Spec:         "8c16g",
				InstanceType: "m5.2xlarge",
				AvailableCPU: "0",
			},
			wantErr: true,
		},
		{
			name: "invalid available memory",
			spec: InstanceTypeSpec{
				Spec:              "8c16g",
				InstanceType:      "m5.2xlarge",
				AvailableMemoryMi: "abc",
			},
			wantErr: true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			err := ValidateInstanceTypeSpec(&tt.spec)
			if tt.wantErr {
				require.Error(t, err)
			} else {
				require.NoError(t, err)
			}
		})
	}
}
