package task

import (
	"context"

	"github.com/tidbcloud/eks-provider/pkg/deploy"
	"github.com/tidbcloud/eks-provider/pkg/k8s"
	"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"

	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/types"
)

const adminNamespace = "tidb-admin"

// Namespace deploys the namespace for TiDB operator and related components.
// It does not implement deletion related functions as the namespaces will
// be removed as part of the cluster deletion itself, i.e. no external resources
// are provisioned during the creation.
type Namespace struct {
	*BaseTask
	namespaces []string
}

func NewNamespace(ctx *Context) *Namespace {
	return &Namespace{
		BaseTask: &BaseTask{Context: ctx},
		namespaces: []string{
			adminNamespace,       // for tidb-operator
			certManagerNamespace, // for cert-manager
			k8s.HelmNamespace},   // for helm
	}
}

func (t *Namespace) Name() string {
	return "Namespace"
}

func (t *Namespace) Create(ctx context.Context) deploy.Result {
	if t.remote == nil {
		return deploy.Skip("empty remote client")
	}
	for _, namespace := range t.namespaces {
		ns := &corev1.Namespace{
			ObjectMeta: metav1.ObjectMeta{
				Name: namespace,
			},
		}
		remote, err := t.remote.GetClient(ctx)
		if err != nil {
			return deploy.FromError(err)
		}
		_, err = controllerutil.CreateOrUpdate(ctx, remote, ns, func() error { return nil })
		if err != nil {
			return deploy.FromError(err)
		}
	}
	return deploy.FromError(nil)
}

func (t *Namespace) PostCreate(ctx context.Context) deploy.Result {
	name := types.NamespacedName{
		Name: adminNamespace,
	}
	var ns corev1.Namespace
	remote, err := t.remote.GetClient(ctx)
	if err != nil {
		return deploy.FromError(err)
	}
	err = remote.Get(ctx, name, &ns)
	return deploy.FromError(err)
}
