package serverless

import (
	"testing"

	"github.com/go-logr/logr/testr"
	"github.com/stretchr/testify/assert"
	observabilitypingcapcomv1 "github.com/tidbcloud/observability/api/regionalserver/resourceworker/v1"
	"github.com/tidbcloud/observability/pkg/common/constants"
	"github.com/tidbcloud/observability/pkg/common/structs"
	"github.com/tidbcloud/observability/pkg/resourceworker/controllers/serverless/task"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"sigs.k8s.io/controller-runtime/pkg/client/fake"
)

func TestInParentCluster_True(t *testing.T) {
	cluster := &observabilitypingcapcomv1.Cluster{
		ObjectMeta: metav1.ObjectMeta{
			Name:      "test-cluster",
			Namespace: "test-namespace",
			Annotations: map[string]string{
				constants.AnnotationShareMode: string(constants.SHARED),
			},
		},
		Spec: observabilitypingcapcomv1.ClusterSpec{
			VictoriaAccount: observabilitypingcapcomv1.VictoriaAccount{
				SupportServerless: true,
			},
		},
	}

	result := inParentCluster(cluster)
	assert.True(t, result)
}

func TestInParentCluster_FalseNoServerless(t *testing.T) {
	cluster := &observabilitypingcapcomv1.Cluster{
		ObjectMeta: metav1.ObjectMeta{
			Name:      "test-cluster",
			Namespace: "test-namespace",
			Annotations: map[string]string{
				constants.AnnotationShareMode: string(constants.SHARED),
			},
		},
		Spec: observabilitypingcapcomv1.ClusterSpec{
			VictoriaAccount: observabilitypingcapcomv1.VictoriaAccount{
				SupportServerless: false,
			},
		},
	}

	result := inParentCluster(cluster)
	assert.False(t, result)
}

func TestInParentCluster_FalseNotShared(t *testing.T) {
	cluster := &observabilitypingcapcomv1.Cluster{
		ObjectMeta: metav1.ObjectMeta{
			Name:      "test-cluster",
			Namespace: "test-namespace",
			Annotations: map[string]string{
				constants.AnnotationShareMode: "not-shared",
			},
		},
		Spec: observabilitypingcapcomv1.ClusterSpec{
			VictoriaAccount: observabilitypingcapcomv1.VictoriaAccount{
				SupportServerless: true,
			},
		},
	}

	result := inParentCluster(cluster)
	assert.False(t, result)
}

func TestInParentCluster_FalseNoAnnotations(t *testing.T) {
	cluster := &observabilitypingcapcomv1.Cluster{
		ObjectMeta: metav1.ObjectMeta{
			Name:      "test-cluster",
			Namespace: "test-namespace",
		},
		Spec: observabilitypingcapcomv1.ClusterSpec{
			VictoriaAccount: observabilitypingcapcomv1.VictoriaAccount{
				SupportServerless: true,
			},
		},
	}

	result := inParentCluster(cluster)
	assert.False(t, result)
}

func TestGetO11yTasks_ParentCluster(t *testing.T) {
	scheme := runtime.NewScheme()
	_ = observabilitypingcapcomv1.AddToScheme(scheme)

	cluster := &observabilitypingcapcomv1.Cluster{
		ObjectMeta: metav1.ObjectMeta{
			Name:      "test-cluster",
			Namespace: "test-namespace",
			Annotations: map[string]string{
				constants.AnnotationShareMode: string(constants.SHARED),
			},
		},
		Spec: observabilitypingcapcomv1.ClusterSpec{
			VictoriaAccount: observabilitypingcapcomv1.VictoriaAccount{
				SupportServerless: true,
			},
		},
	}

	c := &task.Context{
		Local:   fake.NewClientBuilder().WithScheme(scheme).Build(),
		Config:  structs.ServiceInfo{},
		Cluster: cluster,
		Logger:  testr.New(t),
	}

	r := &ServerlessClusterReconciler{}
	tasks := GetO11yTasks(r, c)

	assert.Len(t, tasks, 6)
	taskNames := make([]string, len(tasks))
	for i, task := range tasks {
		taskNames[i] = task.Name()
	}
	assert.Contains(t, taskNames, "Guardian")
	assert.Contains(t, taskNames, "ExternalService")
	assert.Contains(t, taskNames, "Ingress")
	assert.Contains(t, taskNames, "VMAlert")
	assert.Contains(t, taskNames, "EndpointService")
	assert.Contains(t, taskNames, "VMRule")
}

func TestGetO11yTasks_ChildCluster(t *testing.T) {
	scheme := runtime.NewScheme()
	_ = observabilitypingcapcomv1.AddToScheme(scheme)

	cluster := &observabilitypingcapcomv1.Cluster{
		ObjectMeta: metav1.ObjectMeta{
			Name:      "test-cluster",
			Namespace: "test-namespace",
		},
		Spec: observabilitypingcapcomv1.ClusterSpec{
			VictoriaAccount: observabilitypingcapcomv1.VictoriaAccount{
				SupportServerless: false,
			},
		},
	}

	c := &task.Context{
		Local:   fake.NewClientBuilder().WithScheme(scheme).Build(),
		Config:  structs.ServiceInfo{},
		Cluster: cluster,
		Logger:  testr.New(t),
	}

	r := &ServerlessClusterReconciler{}
	tasks := GetO11yTasks(r, c)
	taskNames := make([]string, len(tasks))
	for i, task := range tasks {
		taskNames[i] = task.Name()
	}

	assert.Len(t, tasks, 2)
	assert.Contains(t, taskNames, "Guardian")
	assert.Contains(t, taskNames, "VMRule")
}
