package k8scliv2

import (
	"testing"

	"github.com/aws/smithy-go/ptr"
	xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
	"github.com/stretchr/testify/assert"
	eksv1beta1 "github.com/upbound/provider-aws/apis/eks/v1beta1"
	cpv1beta1 "github.com/upbound/provider-aws/apis/v1beta1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/rest"
	"k8s.io/utils/pointer"
	"sigs.k8s.io/controller-runtime/pkg/client"

	"github.com/tidbcloud/observability/agent-control-server/pkg/consts"
)

func TestEksTenantClientManager_GetClient(t *testing.T) {
	region := "us-west-2"
	clusterName := "test-eks"
	endpoint := "https://test-eks.us-west-2.eks.amazonaws.com"

	tests := []getClientTestCase{
		{
			name: "returns client or exec plugin error for valid config",
			cluster: &eksv1beta1.Cluster{
				ObjectMeta: metav1.ObjectMeta{Name: clusterName},
				Spec: eksv1beta1.ClusterSpec{
					ForProvider: eksv1beta1.ClusterParameters{Region: &region},
				},
				Status: eksv1beta1.ClusterStatus{
					AtProvider: eksv1beta1.ClusterObservation{Endpoint: &endpoint},
				},
			},
			wantErr: false,
		},
		{
			name:    "returns error when config lookup fails",
			cluster: nil,
			wantErr: true,
			errMsg:  "not found",
		},
	}

	runGetClientTests(t, tests, clusterName, NewEKSTenantClientManager, "GetClient")
	runGetClientTests(t, tests, clusterName, NewEKSTenantClientManager, "GetMetricsClient")
}

func TestEksTenantClientManager_GetConfig(t *testing.T) {
	region := "us-west-2"
	clusterName := "test-eks"
	endpoint := "https://test-eks.us-west-2.eks.amazonaws.com"
	publicEndpoint := "https://public-eks.us-west-2.eks.amazonaws.com"
	providerConfigName := "aws-provider"
	roleArn := "arn:aws:iam::123456789012:role/role"
	externalID := "external-id"

	tests := []getConfigTestCase{
		{
			name: "returns config with defaults for v1alpha1",
			cluster: &eksv1beta1.Cluster{
				ObjectMeta: metav1.ObjectMeta{
					Name: clusterName,
				},
				Spec: eksv1beta1.ClusterSpec{
					ForProvider: eksv1beta1.ClusterParameters{
						Region: &region,
					},
				},
				Status: eksv1beta1.ClusterStatus{
					AtProvider: eksv1beta1.ClusterObservation{
						Endpoint: &endpoint,
					},
				},
			},
			verify: func(t *testing.T, cfg *rest.Config) {
				assert.Equal(t, endpoint, cfg.Host)
				assert.Equal(t, "client.authentication.k8s.io/v1alpha1", cfg.ExecProvider.APIVersion)
				assert.Contains(t, cfg.ExecProvider.Args, "--cluster-id")
				assert.Contains(t, cfg.ExecProvider.Args, clusterName)
				assert.NotContains(t, cfg.ExecProvider.Args, "--role")
			},
		},
		{
			name: "uses v1beta1 exec api for kubernetes version 1.24",
			cluster: &eksv1beta1.Cluster{
				ObjectMeta: metav1.ObjectMeta{
					Name: clusterName,
				},
				Spec: eksv1beta1.ClusterSpec{
					ForProvider: eksv1beta1.ClusterParameters{
						Region:  &region,
						Version: ptr.String("1.24"),
					},
				},
				Status: eksv1beta1.ClusterStatus{
					AtProvider: eksv1beta1.ClusterObservation{
						Endpoint: &endpoint,
					},
				},
			},
			verify: func(t *testing.T, cfg *rest.Config) {
				assert.Equal(t, "client.authentication.k8s.io/v1beta1", cfg.ExecProvider.APIVersion)
			},
		},
		{
			name: "uses v1beta1 exec api for kubernetes version 1.30",
			cluster: &eksv1beta1.Cluster{
				ObjectMeta: metav1.ObjectMeta{
					Name: clusterName,
				},
				Spec: eksv1beta1.ClusterSpec{
					ForProvider: eksv1beta1.ClusterParameters{
						Region:  &region,
						Version: ptr.String("1.30"),
					},
				},
				Status: eksv1beta1.ClusterStatus{
					AtProvider: eksv1beta1.ClusterObservation{
						Endpoint: &endpoint,
					},
				},
			},
			verify: func(t *testing.T, cfg *rest.Config) {
				assert.Equal(t, "client.authentication.k8s.io/v1beta1", cfg.ExecProvider.APIVersion)
			},
		},
		{
			name: "uses v1alpha1 exec api for kubernetes version 1.23",
			cluster: &eksv1beta1.Cluster{
				ObjectMeta: metav1.ObjectMeta{
					Name: clusterName,
				},
				Spec: eksv1beta1.ClusterSpec{
					ForProvider: eksv1beta1.ClusterParameters{
						Region:  &region,
						Version: ptr.String("1.23"),
					},
				},
				Status: eksv1beta1.ClusterStatus{
					AtProvider: eksv1beta1.ClusterObservation{
						Endpoint: &endpoint,
					},
				},
			},
			verify: func(t *testing.T, cfg *rest.Config) {
				assert.Equal(t, "client.authentication.k8s.io/v1alpha1", cfg.ExecProvider.APIVersion)
			},
		},
		{
			name: "appends assume role args from provider config",
			cluster: &eksv1beta1.Cluster{
				ObjectMeta: metav1.ObjectMeta{
					Name: clusterName,
				},
				Spec: eksv1beta1.ClusterSpec{
					ForProvider: eksv1beta1.ClusterParameters{
						Region: &region,
					},
					ResourceSpec: xpv1.ResourceSpec{
						ProviderConfigReference: &xpv1.Reference{
							Name: providerConfigName,
						},
					},
				},
				Status: eksv1beta1.ClusterStatus{
					AtProvider: eksv1beta1.ClusterObservation{
						Endpoint: &endpoint,
					},
				},
			},
			setupResources: []client.Object{
				&cpv1beta1.ProviderConfig{
					ObjectMeta: metav1.ObjectMeta{
						Name: providerConfigName,
					},
					Spec: cpv1beta1.ProviderConfigSpec{
						AssumeRoleChain: []cpv1beta1.AssumeRoleOptions{
							{
								RoleARN:    &roleArn,
								ExternalID: &externalID,
							},
						},
					},
				},
			},
			verify: func(t *testing.T, cfg *rest.Config) {
				assert.Contains(t, cfg.ExecProvider.Args, "--role")
				assert.Contains(t, cfg.ExecProvider.Args, roleArn)
				assert.Contains(t, cfg.ExecProvider.Args, "--external-id")
				assert.Contains(t, cfg.ExecProvider.Args, externalID)
			},
		},
		{
			name: "uses annotated public endpoint when public access is disabled",
			cluster: &eksv1beta1.Cluster{
				ObjectMeta: metav1.ObjectMeta{
					Name: clusterName,
					Annotations: map[string]string{
						consts.AnnotationKeyEKSEndpoint: publicEndpoint,
					},
				},
				Spec: eksv1beta1.ClusterSpec{
					ForProvider: eksv1beta1.ClusterParameters{
						Region: &region,
						VPCConfig: []eksv1beta1.VPCConfigParameters{
							{
								EndpointPublicAccess: pointer.Bool(false),
							},
						},
					},
				},
				Status: eksv1beta1.ClusterStatus{
					AtProvider: eksv1beta1.ClusterObservation{
						Endpoint: &endpoint,
					},
				},
			},
			verify: func(t *testing.T, cfg *rest.Config) {
				assert.Equal(t, publicEndpoint, cfg.Host)
			},
		},
		{
			name:    "returns error when cluster is not found",
			cluster: nil,
			wantErr: true,
			errMsg:  "not found",
		},
		{
			name: "returns error when provider config is not found",
			cluster: &eksv1beta1.Cluster{
				ObjectMeta: metav1.ObjectMeta{
					Name: clusterName,
				},
				Spec: eksv1beta1.ClusterSpec{
					ForProvider: eksv1beta1.ClusterParameters{
						Region: &region,
					},
					ResourceSpec: xpv1.ResourceSpec{
						ProviderConfigReference: &xpv1.Reference{
							Name: "missing-config",
						},
					},
				},
			},
			wantErr: true,
			errMsg:  "not found",
		},
	}

	runGetConfigTests(t, tests, clusterName, NewEKSTenantClientManager)
}
