package utils

import (
	"errors"
	"flag"
	"github.com/astaxie/beego"
	"github.com/astaxie/beego/logs"
	"k8s.io/api/core/v1"
	k8sapierrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/kubernetes"
	_ "k8s.io/client-go/plugin/pkg/client/auth/oidc"
	"k8s.io/client-go/tools/clientcmd"
)

var (
	infoLogger  = logs.GetLogger("info")
	errorLogger = logs.GetLogger("error")
	kubeconfig  = flag.String("config", beego.AppConfig.String("configPath"), "kubeconfig file path")
	//当前命名空间
	nameSpace = beego.AppConfig.String("nameSpace")
)

// 获取k8s客户端
func GetK8sClient() *kubernetes.Clientset {
	flag.Parse()
	config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
	if err != nil {
		infoLogger.Println(err.Error())
		return nil
	}
	//创建k8s客户端对象
	clientset, err := kubernetes.NewForConfig(config)
	if err != nil {
		errorLogger.Println(err.Error())
		return nil
	}
	return clientset
}

// 获取集群所有命名空间
func GetClusterAllNameSpaces(lang string) ([]string, error) {
	result := []string{}

	// 获取k8s客户端
	k8sClient := GetK8sClient()
	if k8sClient == nil {
		return result, errors.New(GetI18nLang(lang, "createK8sConFail"))
	}
	//查询集群所有命名空间信息
	nameSpaceList, err := k8sClient.CoreV1().Namespaces().List(metav1.ListOptions{})
	if err != nil {
		errorLogger.Printf("查询集群所有命名空间失败: %s", err.Error())
		return result, errors.New(GetI18nLang(lang, "getClusterAllNamespacesFail"))
	}

	for _, item := range nameSpaceList.Items {
		result = append(result, item.Name)
	}

	//是否显示当前命名空间 默认不显示
	displayCurrentNameSpace := false

	// 获取k8s-console-config configMap里面的内容 是否显示当前空间
	k8sConfigMap, err := k8sClient.CoreV1().ConfigMaps(nameSpace).Get("k8s-console-config", metav1.GetOptions{})
	if k8sapierrors.IsNotFound(err) {
		infoLogger.Println("执行创建名称为k8s-console-config的configMap")

		newConfigMap := v1.ConfigMap{}
		newConfigMap.TypeMeta = metav1.TypeMeta{"ConfigMap", "v1"}
		objectMeta := metav1.ObjectMeta{}
		objectMeta.Name = "k8s-console-config"
		objectMeta.Namespace = nameSpace
		newConfigMap.ObjectMeta = objectMeta
		newConfigMap.Data = map[string]string{"displayCurrentNameSpace": "false"}

		if _, err = k8sClient.CoreV1().ConfigMaps(nameSpace).Create(&newConfigMap); err != nil {
			errorLogger.Printf("创建集群%s空间名称为k8s-console-config的configMap失败: %s", nameSpace, err.Error())
			return result, errors.New(GetI18nLang(lang, "getClusterAllNameSpaces_createK8sConsoleConfigConfigMapFail"))
		}
		infoLogger.Println("创建名称为k8s-console-config的configMap成功")

	} else {
		if err != nil {
			errorLogger.Printf("查询集群%s空间是否存在名称为k8s-console-config的configMap失败: %s", nameSpace, err.Error())
			return result, errors.New(GetI18nLang(lang, "getClusterAllNameSpaces_queryK8sConsoleConfigConfigMapExistFail"))
		}
		data := k8sConfigMap.Data
		if _, ok := data["displayCurrentNameSpace"]; ok {
			if data["displayCurrentNameSpace"] == "true" {
				displayCurrentNameSpace = true
			}
		}
	}

	//如果不显示当前命名空间 则过滤
	if !displayCurrentNameSpace {
		// 目前暂不过滤当前命名空间
		//for i, v := range result {
		//	if v == nameSpace {
		//		result = append(result[:i], result[i+1:]...)
		//	}
		//}
	}

	return result, nil
}

// 资源对象结构体
type ResourceQuotaResourceLimitData struct {
	NameSpace        string `json:"nameSpace"`        //命名空间
	AvailableCpu     string `json:"availableCpu"`     //可用cpu加单位(m,g) 默认m
	AvailableMemory  string `json:"availableMemory"`  //可用内存加单位(Mi,Gi) 默认Mi
	AvailableStorage string `json:"availableStorage"` //可用存储加单位(Mi,Gi) 默认Mi
	PVCNumber        int    `json:"pVCNumber"`        //存储卷声明个数
	AvailableDeploy  int    `json:"availableDeploy"`  //可用部署个数
	AvailablePod     int    `json:"availablePod"`     //可用pod个数
	AvailableService int    `json:"availableService"` //可用服务个数
	AvailableIngress int    `json:"availableIngress"` //可用负载个数
}

//查询资源限制对象ResourceQuota
func GetResourceQuotaResourceLimitData(ns, lang string) (ResourceQuotaResourceLimitData, error) {
	dto := ResourceQuotaResourceLimitData{}
	// 获取k8s连接
	k8sClient := GetK8sClient()
	if k8sClient == nil {
		return dto, errors.New(GetI18nLang(lang, "createK8sConFail"))
	}
	// 名称默认是命名空间加上-resourcequota
	resourceQuotaName := ns + "-resourcequota"
	resourceQuota, err := k8sClient.CoreV1().ResourceQuotas(ns).Get(resourceQuotaName, metav1.GetOptions{})
	if err != nil {
		errorLogger.Printf("查询%s命名空间ResourceQuota: %s失败:%s", ns, resourceQuotaName, err.Error())
		return dto, err
	}
	resourceMap := resourceQuota.Spec.Hard
	if len(resourceMap) > 0 {
		for k, v := range resourceMap {
			switch k {
			case "persistentvolumeclaims":
				dto.PVCNumber = int(v.Value())
			case "count/deployments.extensions":
				dto.AvailableDeploy = int(v.Value())
			case "pods":
				dto.AvailablePod = int(v.Value())
			case "services":
				dto.AvailableService = int(v.Value())
			case "count/ingresses.extensions":
				dto.AvailableIngress = int(v.Value())

			}
		}
	}

	return dto, nil
}

//查询资源限制对象LimitRange
func GetLimitRangeResourceLimitData(ns, lang string) (ResourceQuotaResourceLimitData, error) {
	dto := ResourceQuotaResourceLimitData{}
	// 获取k8s连接
	k8sClient := GetK8sClient()
	if k8sClient == nil {
		return dto, errors.New(GetI18nLang(lang, "createK8sConFail"))
	}
	// 名称默认是命名空间加上-limitrange
	limitRangeName := ns + "-limitrange"
	limitRange, err := k8sClient.CoreV1().LimitRanges(dto.NameSpace).Get(limitRangeName, metav1.GetOptions{})
	if err != nil {
		errorLogger.Printf("查询%s命名空间LimitRange: %s失败:%s", ns, limitRangeName, err.Error())
		return dto, err
	}
	limitRangeItemList := limitRange.Spec.Limits
	if len(limitRangeItemList) > 0 {
		for _, item := range limitRangeItemList {
			switch item.Type {
			case v1.LimitTypeContainer:
				if val, ok := item.Max[v1.ResourceCPU]; ok {
					dto.AvailableCpu = val.String()
				}
				if val, ok := item.Max[v1.ResourceMemory]; ok {
					dto.AvailableMemory = val.String()
				}
			case v1.LimitTypePersistentVolumeClaim:
				if val, ok := item.Max[v1.ResourceStorage]; ok {
					dto.AvailableStorage = val.String()
				}
			}
		}
	}

	return dto, nil
}
