package service

import (
	"testing"

	. "github.com/onsi/gomega"
	opv2 "github.com/pingcap/tidb-operator/api/v2/core/v1alpha1"
	v1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func buildTestPod(component string, annotations map[string]string) *v1.Pod {
	return &v1.Pod{
		ObjectMeta: metav1.ObjectMeta{
			Name: "db-" + component + "-0",
			Labels: map[string]string{
				componentLabelKey:      component,
				opv2.LabelKeyComponent: component,
			},
			Annotations: annotations,
		},
	}
}

func Test_getCloudProviderFromNode(t *testing.T) {
	tests := []struct {
		name        string
		providerID  string
		expected    string
		expectError bool
	}{
		{
			name:        "valid AWS providerID",
			providerID:  "aws:///us-west-2a/i-xxxxx",
			expected:    "aws",
			expectError: false,
		},
		{
			name:        "valid GCE providerID",
			providerID:  "gce://project-id/us-west1-b/gke-xxx-node-po-xxx",
			expected:    "gcp",
			expectError: false,
		},
		{
			name:        "valid azure provider",
			providerID:  "azure:///us-west-2a/xxxxx",
			expected:    "azure",
			expectError: false,
		},
		{
			name:        "empty providerID",
			providerID:  "",
			expected:    "",
			expectError: true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			g := NewGomegaWithT(t)
			node := &v1.Node{
				Spec: v1.NodeSpec{
					ProviderID: tt.providerID,
				},
			}
			provider, err := getCloudProviderFromNode(node)
			if tt.expectError {
				g.Expect(err).To(HaveOccurred())
			} else {
				g.Expect(err).NotTo(HaveOccurred())
				g.Expect(provider).To(Equal(tt.expected))
			}
		})
	}
}

func Test_parseEKSNodeProviderID(t *testing.T) {
	tests := []struct {
		name           string
		providerID     string
		expectedRegion string
		expectedID     string
		expectError    bool
	}{
		{
			name:           "valid EKS providerID",
			providerID:     "aws:///us-west-2a/i-xxxxx",
			expectedRegion: "us-west-2",
			expectedID:     "i-xxxxx",
			expectError:    false,
		},
		{
			name:        "invalid EKS providerID",
			providerID:  "invalid-provider-id",
			expectedID:  "",
			expectError: true,
		},
		{
			name:        "empty providerID",
			providerID:  "",
			expectedID:  "",
			expectError: true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			g := NewGomegaWithT(t)
			region, id, err := parseEKSNodeProviderID(tt.providerID)
			if tt.expectError {
				g.Expect(err).To(HaveOccurred())
			} else {
				g.Expect(err).NotTo(HaveOccurred())
				g.Expect(region).To(Equal(tt.expectedRegion))
				g.Expect(id).To(Equal(tt.expectedID))
			}
		})
	}
}

func Test_parseGKENodeProviderID(t *testing.T) {
	tests := []struct {
		name                 string
		providerID           string
		expectedProjectID    string
		expectedZone         string
		expectedInstanceName string
		expectError          bool
	}{
		{
			name:                 "valid GKE providerID",
			providerID:           "gce://project-id/us-west1-b/gke-xxx-node-po-xxx",
			expectedProjectID:    "project-id",
			expectedZone:         "us-west1-b",
			expectedInstanceName: "gke-xxx-node-po-xxx",
			expectError:          false,
		},
		{
			name:                 "invalid GKE providerID 1",
			providerID:           "gce://project-id/us-west1-b/",
			expectedProjectID:    "",
			expectedZone:         "",
			expectedInstanceName: "",
			expectError:          true,
		},
		{
			name:                 "invalid GKE providerID 2",
			providerID:           "aws:///us-west-2a/i-xxxxx",
			expectedProjectID:    "",
			expectedZone:         "",
			expectedInstanceName: "",
			expectError:          true,
		},
		{
			name:                 "empty providerID",
			providerID:           "",
			expectedProjectID:    "",
			expectedZone:         "",
			expectedInstanceName: "",
			expectError:          true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			g := NewGomegaWithT(t)
			pid, z, in, err := parseGKENodeProviderID(tt.providerID)
			if tt.expectError {
				g.Expect(err).To(HaveOccurred())
			} else {
				g.Expect(err).NotTo(HaveOccurred())
				g.Expect(pid).To(Equal(tt.expectedProjectID))
				g.Expect(z).To(Equal(tt.expectedZone))
				g.Expect(in).To(Equal(tt.expectedInstanceName))
			}
		})
	}
}
