package job

import (
	"context"
	"encoding/json"

	"github.com/juju/errors"
	log "github.com/sirupsen/logrus"
	"github.com/tidbcloud/auto-deploy/internal/constants"
	batchapi "k8s.io/api/batch/v1"
	apiv1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	applyv1 "k8s.io/client-go/applyconfigurations/core/v1"
	"k8s.io/client-go/kubernetes"
	"sigs.k8s.io/yaml"
)

func ApplyCloudAuthSecret(clientset *kubernetes.Clientset, secret string) error {
	client := clientset.CoreV1().Secrets(apiv1.NamespaceDefault)

	var sec applyv1.SecretApplyConfiguration
	jsonContent, err := yaml.YAMLToJSON([]byte(secret))
	if err != nil {
		return errors.Annotatef(err, "Failed to convert secret yaml to json")
	}
	if err := json.Unmarshal(jsonContent, &sec); err != nil {
		return errors.Annotatef(err, "Failed to unmarshal secret")
	}
	_, err = client.Apply(context.TODO(), &sec, metav1.ApplyOptions{
		FieldManager: constants.K8S_APPLY_FIELD_MANAGER,
	})
	if err != nil {
		log.WithField("name", *sec.Name).Error("Failed to apply secret")
		return errors.Annotatef(err, "Failed to apply secret: %s", *sec.Name)
	}
	log.WithField("secret-yaml", secret).Debug("Apply secret")
	log.WithField("secret", *sec.ObjectMetaApplyConfiguration.Name).Info("Apply secret")
	return nil
}

func ApplyCommonSecret(clientset *kubernetes.Clientset, secretMap map[string]string) error {
	sec := applyv1.Secret(constants.COMMON_SECRET, apiv1.NamespaceDefault).WithStringData(secretMap)

	client := clientset.CoreV1().Secrets(apiv1.NamespaceDefault)
	_, err := client.Apply(context.TODO(), sec, metav1.ApplyOptions{
		FieldManager: constants.K8S_APPLY_FIELD_MANAGER,
	})
	if err != nil {
		log.WithField("name", *sec.Name).Error("Failed to apply secret")
		return errors.Annotatef(err, "Failed to apply secret: %s", *sec.Name)
	}
	return nil
}

func MoutCloudAuthSecret(job *batchapi.Job, secretName, path string, subPaths []string) {
	containers := job.Spec.Template.Spec.InitContainers
	if len(containers) == 0 {
		containers = job.Spec.Template.Spec.Containers
	}
	for i := range containers {
		for _, subPath := range subPaths {
			containers[i].VolumeMounts = append(containers[i].VolumeMounts, apiv1.VolumeMount{
				Name:      secretName,
				ReadOnly:  true,
				MountPath: path + "/" + subPath,
				SubPath:   subPath,
			})
		}
		log.WithFields(log.Fields{
			"job-name":    job.Name,
			"container":   containers[i].Name,
			"secret-name": secretName,
			"mount-path":  path,
		}).Debug("Mount secret to job")
	}
	job.Spec.Template.Spec.Volumes = append(job.Spec.Template.Spec.Volumes, apiv1.Volume{
		Name: secretName,
		VolumeSource: apiv1.VolumeSource{
			Secret: &apiv1.SecretVolumeSource{
				SecretName: secretName,
			},
		},
	})
	log.WithFields(log.Fields{
		"job-name":    job.Name,
		"secret-name": secretName,
	}).Debug("Mout secret volume to job")
}
