package models

import (
	"errors"
	"github.com/astaxie/beego/logs"
	"k8s-console/utils"
	coreV1 "k8s.io/api/core/v1"
	scV1 "k8s.io/api/storage/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/kubernetes/scheme"
	"sigs.k8s.io/yaml"
	"strings"
)

type ScBean struct {
	Name          string `json:"name"`
	Provisioner   string `json:"provisioner"`
	ReclaimPolicy string `json:"reclaimPolicy"`
	CreateTime    string `json:"createTime"`
}

/**
  查询所有存储类
*/
func GetAllSc(lang string) ([]ScBean, error) {
	var beans []ScBean
	k8sClient := utils.GetK8sClient()
	if k8sClient == nil {
		return nil, errors.New("连接k8s集群失败")
	}
	storageClassList, err := k8sClient.StorageV1().StorageClasses().List(v1.ListOptions{})
	if err != nil {
		logs.Error("查询sc失败：", err.Error())
		return nil, err
	}
	storageClasses := storageClassList.Items
	if len(storageClasses) > 0 {
		for _, v := range storageClasses {
			bean := ScBean{}

			bean.Name = v.Name
			bean.Provisioner = v.Provisioner
			policy := v.ReclaimPolicy
			bean.ReclaimPolicy = *(*string)(policy)
			bean.CreateTime = utils.GetDurationToString(lang, v.CreationTimestamp.Time, true)

			beans = append(beans, bean)
		}
		return beans, nil
	}
	return nil, errors.New("查询sc失败")
}

/**
  根据sc名称删除存储类
*/
func DeleteScByScName(scName string) error {

	k8sClient := utils.GetK8sClient()
	if k8sClient == nil {
		return errors.New("连接k8s集群失败")
	}
	// 判断scName是否被pv使用
	flag, err := IsApplyByPv(scName)
	if err != nil {
		return errors.New("删除sc检测是否使用查询pv失败")
	}
	if flag {
		return errors.New("sc被使用，不能删除")
	}
	err = k8sClient.StorageV1().StorageClasses().Delete(scName, &v1.DeleteOptions{})
	if err != nil {
		return errors.New("sc未被使用，删除sc失败")
	}
	return nil
}

/**
  检测存储类  是否被使用
*/
func IsApplyByPv(scName string) (bool, error) {
	var flag = false
	k8sClient := utils.GetK8sClient()
	if k8sClient == nil {
		return flag, errors.New("连接k8s集群失败")
	}
	volumeList, err := k8sClient.CoreV1().PersistentVolumes().List(v1.ListOptions{})
	if err != nil {
		return flag, err
	}
	persistentVolumes := volumeList.Items
	if len(persistentVolumes) > 0 {
		for _, v := range persistentVolumes {
			if scName == v.Spec.StorageClassName {
				flag = true
				return flag, nil
			}
		}
	}
	return flag, nil
}

/**
  校验存储类
*/
func CheckSc(lang string, scOption scV1.StorageClass) error {

	if strings.TrimSpace(scOption.TypeMeta.APIVersion) != "storage.k8s.io/v1" {
		errorLogger.Println("ApiVersion值有误")
		return errors.New(utils.GetI18nLang(lang, "scApiVersionFail"))
	}

	if strings.TrimSpace(scOption.TypeMeta.Kind) == "" || strings.TrimSpace(scOption.TypeMeta.Kind) != "StorageClass" {
		errorLogger.Println("Kind值有误")
		return errors.New(utils.GetI18nLang(lang, "scKindFail"))
	}

	if strings.TrimSpace(scOption.Provisioner) == "" {
		errorLogger.Println("Provisioner 不能为空")
		return errors.New(utils.GetI18nLang(lang, "scProvisionerFail"))
	}

	if strings.TrimSpace(scOption.Name) == "" {
		errorLogger.Println("sc 名称不能为空")
		return errors.New(utils.GetI18nLang(lang, "scProvisionerFail"))
	}
	if scOption.ReclaimPolicy != nil {
		if !((*scOption.ReclaimPolicy == coreV1.PersistentVolumeReclaimDelete) || (*scOption.ReclaimPolicy == "Recycle") || (*scOption.ReclaimPolicy == "Retain")) {
			return errors.New(utils.GetI18nLang(lang, "scReclaimPolicyFail"))
		}
	}
	if scOption.VolumeBindingMode != nil {
		if !(*scOption.VolumeBindingMode == scV1.VolumeBindingImmediate || *scOption.VolumeBindingMode == scV1.VolumeBindingWaitForFirstConsumer) {
			return errors.New(utils.GetI18nLang(lang, "scVolumeBindingModeFail"))
		}
	}
	// 转换yaml格式
	yamlBytes, err := yaml.Marshal(scOption)
	if err != nil {
		errorLogger.Printf("转换yaml失败: %s", err.Error())
		return errors.New(utils.GetI18nLang(lang, "invalidPvcFormat"))
	}
	infoLogger.Println("\n" + string(yamlBytes))

	decode := scheme.Codecs.UniversalDeserializer()
	_, _, err = decode.Decode(yamlBytes, nil, nil)
	if err != nil {
		errorLogger.Printf("转换yaml文件失败: %s", err.Error())
		return errors.New(utils.GetI18nLang(lang, "invalidPvcFormat"))
	}
	return nil
}

/**
  创建存储类
*/
func CreateSc(lang string, scOptions scV1.StorageClass) error {
	k8sClient := utils.GetK8sClient()
	if k8sClient == nil {
		return errors.New("连接k8s集群失败")
	}
	//检查是否存在
	_, err := k8sClient.StorageV1().StorageClasses().Get(scOptions.Name, v1.GetOptions{})
	if err != nil {
		// 不存在 创建 存储类
		_, err := k8sClient.StorageV1().StorageClasses().Create(&scOptions)
		if err != nil {
			return errors.New(utils.GetI18nLang(lang, "scCreateFail"))
		}
	} else {
		//存在此 存储类
		return errors.New(utils.GetI18nLang(lang, "scExist"))
	}
	return nil
}
