package branch

import (
	"context"
	"testing"

	"github.com/aws/aws-sdk-go-v2/aws"
	"github.com/go-logr/logr"
	. "github.com/onsi/gomega"
	"github.com/tidbcloud/aws-shared-provider/pkg/o11y"
	"github.com/tidbcloud/aws-shared-provider/pkg/utils"
	cloudv1 "github.com/tidbcloud/infra-api/api/v1"
	"github.com/tidbcloud/infra-api/pkg/consts"
	o11ymetric "github.com/tidbcloud/infra-api/pkg/o11y/metric_agent"
	infrao11y "github.com/tidbcloud/observability/agent-control-server/pkg/o11y/api"
	infrao11yfake "github.com/tidbcloud/observability/agent-control-server/pkg/o11y/api/fake"
	gomock "go.uber.org/mock/gomock"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/kubernetes/scheme"
	"sigs.k8s.io/controller-runtime/pkg/client/fake"
)

func TestO11yClusterServerless(t *testing.T) {
	// Define crd objects
	region := "us-west-2"
	o11yID := "fake-o11y-id"
	branch01 := &cloudv1.Branch{
		ObjectMeta: metav1.ObjectMeta{
			Name: "branch_01",
			Labels: map[string]string{
				cloudv1.RegionLabel: region,
			},
			Annotations: map[string]string{
				utils.TiDBBranchMetadataAnnKey: `{
					"tenant-id": 121,
					"project-id": 122,
					"id": "branch_01"
				}`,
			},
		},
		Spec: cloudv1.BranchSpec{
			Cluster: cloudv1.ClusterTopology{
				TiDB: cloudv1.TiDB{Replicas: 1},
			},
		},
	}

	// Set up context
	g := NewGomegaWithT(t)
	g.Expect(cloudv1.AddToScheme(scheme.Scheme)).Should(Succeed())
	infraClient := fake.NewClientBuilder().WithScheme(scheme.Scheme).
		WithObjects(branch01).Build()
	client := fake.NewClientBuilder().WithObjects().Build()
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()
	o11yApi := infrao11yfake.NewMockApi(ctrl)
	//nolint:lll // ignore
	o11yApi.EXPECT().CreateO11yInfraV2Serverless(
		gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(
		&infrao11y.ObservabilityCluster{
			ClusterBaseInfo: infrao11y.ClusterBaseInfo{
				ID: o11yID,
			},
			MonitorInfo: infrao11y.MonitorInfo{
				EndpointServiceName: "fake-endpoint-service-name",
				DnsName:             aws.String("fake-dns-name"),
			},
			Status: infrao11y.ACTIVE,
		}, nil).MinTimes(1)
	o11yApi.EXPECT().DeleteO11yInfra(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(
		&infrao11y.ObservabilityCluster{}, nil).MinTimes(1)
	r := &reconcileContext{Logger: logr.Discard()}
	r.Reconciler = &Reconciler{Logger: logr.Discard()}
	r.ctx = context.Background()
	r.Client = client
	r.InfraClient = infraClient
	r.branch = branch01
	r.KubeClusterName = "dev-us-east-1-f01"
	r.O11yApi = o11yApi
	r.O11yConfig = &cloudv1.ObservabilityInfraConfig{
		Version: 0,
	}

	// Run the creation.
	err := r.ensureO11yCluster()

	// Check the creation output.
	g.Expect(err).Should(Succeed())

	remoteWrite := o11ymetric.NewWriteURLBuilder("fake-dns-name").ForAWS().
		BuildRemoteWrite(o11yID)

	// Assert o11y annotations are added to cluster crd.
	g.Expect(branch01.Annotations).Should(HaveKeyWithValue(o11y.O11yClusterRemoteWriteAnnotationKey, remoteWrite))
	g.Expect(branch01.Annotations).Should(HaveKeyWithValue(consts.O11yIDAnnotationKey, o11yID))

	// Run the deletion.
	err = r.deleteO11yCluster()

	// Check the deletion output.
	g.Expect(err).Should(Succeed())
}
