package kubernetes

import (
	"context"
	"fmt"
	"time"

	"github.com/pingcap/log"
	opv2 "github.com/pingcap/tidb-operator/api/v2/core/v1alpha1"
	"github.com/pingcap/tidb-operator/pkg/client/clientset/versioned"
	tidbclusterInformers "github.com/pingcap/tidb-operator/pkg/client/informers/externalversions"

	"github.com/tidbcloud/sli-reporter/slprober"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/client-go/dynamic"
	kubeinformers "k8s.io/client-go/informers"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
	"sigs.k8s.io/controller-runtime/pkg/client"
)

var (
	resyncDuration = 30 * time.Second

	clientset *kubernetes.Clientset

	dynamicClient *dynamic.DynamicClient

	TiDBClusterInformerFactory tidbclusterInformers.SharedInformerFactory

	Prober *slprober.ServiceLevelProber
)

func InitConfig() error {
	log.Info("Create in-cluster config")
	config, err := rest.InClusterConfig()
	if err != nil {
		return err
	}
	config.Timeout = time.Second * 2

	// creates dynamic client, used to check whether tidbcluster crd exists
	dynamicClient, err = dynamic.NewForConfig(config)
	if err != nil {
		return fmt.Errorf("failed to create dynamic client: %w", err)
	}

	// creates the clientset
	clientset, err = kubernetes.NewForConfig(config)
	if err != nil {
		return err
	}
	cli, err := versioned.NewForConfig(config)
	if err != nil {
		return fmt.Errorf("failed to create clientset: %s", err.Error())
	}

	// Init the cluster informer
	TiDBClusterInformerFactory = tidbclusterInformers.NewSharedInformerFactory(cli, resyncDuration)
	stopCh := make(chan struct{})
	informer := kubeinformers.NewSharedInformerFactory(clientset, resyncDuration)

	// Init
	scheme := runtime.NewScheme()
	err = opv2.Install(scheme)
	if err != nil {
		return fmt.Errorf("failed to add to schema: %v", err.Error())
	}

	// init the k8s client, used to list tidbgroup and tiproxygroup
	client, err := client.New(config, client.Options{Scheme: scheme})
	if err != nil {
		return fmt.Errorf("failed to create ctrl client: %v", err.Error())
	}

	// init the cluster prober
	Prober = slprober.NewServiceLevelProber(clientset, client, TiDBClusterInformerFactory)

	informer.Start(stopCh)
	informer.WaitForCacheSync(stopCh)

	return nil
}

func CheckTiDBClusterCRDExists(ctx context.Context) bool {
	if dynamicClient == nil {
		return false
	}

	gvr := schema.GroupVersionResource{
		Group:    "pingcap.com",
		Version:  "v1alpha1",
		Resource: "tidbclusters",
	}

	r, err := dynamicClient.Resource(gvr).Namespace("").List(ctx, metav1.ListOptions{})
	if err != nil || r == nil {
		return false
	}

	return true
}
