package controller

import (
	"fmt"
	"sort"
	"strings"
	"time"

	"github.com/tidbcloud/tiinf/monitor/tilog"
	"go.uber.org/zap"
	"k8s.io/apimachinery/pkg/labels"
	"k8s.io/apimachinery/pkg/util/wait"
	"k8s.io/client-go/informers"
	"k8s.io/client-go/kubernetes"
	appsv1lister "k8s.io/client-go/listers/apps/v1"
	"k8s.io/client-go/rest"
)

var controllerObj *Controller

type Controller struct {
	deploymentLister appsv1lister.DeploymentLister
}

func Init(cfg *rest.Config) {
	kubeClient, err := kubernetes.NewForConfig(cfg)
	if err != nil {
		tilog.PlainFatal("Error building kubernetes clientset", zap.Error(err))
	}
	kubeInformerFactory := informers.NewSharedInformerFactory(kubeClient, time.Minute*10)
	deploymentInformer := kubeInformerFactory.Apps().V1().Deployments()
	controllerObj = &Controller{
		deploymentLister: deploymentInformer.Lister(),
	}
	kubeInformerFactory.Start(wait.NeverStop)
	kubeInformerFactory.WaitForCacheSync(wait.NeverStop)
}

type KubeDeployment struct {
	Name              string `json:"name"`
	NameSpace         string `json:"namespace"`
	DesiredReplicas   int32  `json:"desired_replicas"`
	AvailableReplicas int32  `json:"available_replicas"`
}

func ListDeployments(namespaces string) ([]*KubeDeployment, error) {
	var deployments []*KubeDeployment

	// Split the namespaces string into a slice of namespace names.
	namespaceList := strings.Split(namespaces, ",")

	for _, namespace := range namespaceList {
		// Trim any extra spaces around the namespace.
		namespace = strings.TrimSpace(namespace)

		// Skip empty namespaces.
		if namespace == "" {
			continue
		}
		tilog.PlainInfo("list deployments for namespace: " + namespace)

		// Call ListDeploymentsByNamespace for each namespace.
		nsDeployments, err := ListDeploymentsByNameSpace(namespace)
		if err != nil {
			return nil, fmt.Errorf("failed to list deployments for namespace '%s': %w", namespace, err)
		}

		// Append the deployments from this namespace to the result list.
		deployments = append(deployments, nsDeployments...)
	}
	return deployments, nil
}
func ListDeploymentsByNameSpace(namespace string) ([]*KubeDeployment, error) {
	deployments, err := controllerObj.deploymentLister.Deployments(namespace).List(labels.NewSelector())
	if err != nil {
		return nil, err
	}
	kubeDeployments := make([]*KubeDeployment, 0, 10)
	for _, deployment := range deployments {
		kubeDeployments = append(kubeDeployments, &KubeDeployment{
			Name:              deployment.Name,
			NameSpace:         namespace,
			DesiredReplicas:   *deployment.Spec.Replicas,
			AvailableReplicas: deployment.Status.AvailableReplicas,
		})
		tilog.PlainInfo("list deployment " + deployment.Name + " for namespace: " + namespace)
	}
	sort.Slice(kubeDeployments, func(i, j int) bool {
		return len(kubeDeployments[i].Name) < len(kubeDeployments[j].Name)
	})
	return kubeDeployments, nil
}
