package v1

import (
	"fmt"

	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/util/validation/field"
	ctrl "sigs.k8s.io/controller-runtime"
	logf "sigs.k8s.io/controller-runtime/pkg/log"
	"sigs.k8s.io/controller-runtime/pkg/webhook"
	"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
)

// log is for logging in this package.
var exportlog = logf.Log.WithName("export-resource")

func (r *Export) setupWebhookWithManager(mgr ctrl.Manager) error {
	return ctrl.NewWebhookManagedBy(mgr).
		For(r).
		Complete()
}

// TODO(user): EDIT THIS FILE!  THIS IS SCAFFOLDING FOR YOU TO OWN!

//+kubebuilder:webhook:path=/mutate-cloud-pingcap-com-v1-export,mutating=true,failurePolicy=fail,sideEffects=None,groups=cloud.pingcap.com,resources=exports,verbs=create;update,versions=v1,name=mexport.kb.io,admissionReviewVersions={v1,v1beta1}

var _ webhook.Defaulter = &Export{}

// Default implements webhook.Defaulter so a webhook will be registered for the type
func (r *Export) Default() {
	exportlog.Info("webhook default", "name", r.Name)
}

// TODO(user): change verbs to "verbs=create;update;delete" if you want to enable deletion validation.
//+kubebuilder:webhook:path=/validate-cloud-pingcap-com-v1-export,mutating=false,failurePolicy=fail,sideEffects=None,groups=cloud.pingcap.com,resources=exports,verbs=create;update,versions=v1,name=vexport.kb.io,admissionReviewVersions={v1,v1beta1}

var _ webhook.Validator = &Export{}

// ValidateCreate implements webhook.Validator so a webhook will be registered for the type
func (r *Export) ValidateCreate() (admission.Warnings, error) {
	exportlog.Info("validate create", "name", r.Name)

	var allErrs field.ErrorList
	if r.GetLabels()[ProviderTypeLabel] == "" {
		allErrs = append(allErrs, field.Invalid(field.NewPath("metadata").Child("labels"), r.GetLabels()[ProviderTypeLabel],
			fmt.Sprintf("%s label is missing", ProviderTypeLabel)))
	}
	if r.GetLabels()[LabelKubernetes] == "" {
		allErrs = append(allErrs, field.Invalid(field.NewPath("metadata").Child("labels"), r.GetLabels()[LabelKubernetes],
			fmt.Sprintf("%s label is missing", LabelKubernetes)))
	}

	return nil, invalidOrNil(allErrs, r)
}

// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type
func (r *Export) ValidateUpdate(old runtime.Object) (admission.Warnings, error) {
	exportlog.Info("validate update", "name", r.Name)

	var allErrs field.ErrorList
	oldE := old.(*Export)
	if r.Spec.ClusterName != oldE.Spec.ClusterName {
		allErrs = append(allErrs, field.Invalid(field.NewPath("spec").Child("clusterName"), r.Spec.ClusterName, "field is immutable"))
	}
	if r.GetLabels()[ProviderTypeLabel] != oldE.GetLabels()[ProviderTypeLabel] {
		allErrs = append(allErrs, field.Invalid(field.NewPath("metadata").Child("labels"), r.GetLabels()[ProviderTypeLabel],
			fmt.Sprintf("%s label is immutable", ProviderTypeLabel)))
	}
	if r.GetLabels()[LabelKubernetes] != oldE.GetLabels()[LabelKubernetes] {
		allErrs = append(allErrs, field.Invalid(field.NewPath("metadata").Child("labels"), r.GetLabels()[LabelKubernetes],
			fmt.Sprintf("%s label is immutable", LabelKubernetes)))
	}

	return nil, invalidOrNil(allErrs, r)
}

// ValidateDelete implements webhook.Validator so a webhook will be registered for the type
func (r *Export) ValidateDelete() (admission.Warnings, error) {
	exportlog.Info("validate delete", "name", r.Name)

	// TODO(user): fill in your validation logic upon object deletion.
	return nil, nil
}
