package resourcemanager

import (
	"context"

	"github.com/tidbcloud/observability/pkg/common/configs"

	"github.com/tidbcloud/observability/pkg/common/constants"

	"github.com/tidbcloud/observability/pkg/common/errors"
	apierrors "k8s.io/apimachinery/pkg/api/errors"

	v1 "k8s.io/api/core/v1"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/kubernetes"
	"sigs.k8s.io/controller-runtime/pkg/client"
)

type namespaceReaderWriter struct {
	kubeClient kubernetes.Interface
}

func (n namespaceReaderWriter) Create(ctx context.Context, namespace *v1.Namespace) error {
	_, err := n.kubeClient.CoreV1().
		Namespaces().Create(ctx, namespace, metav1.CreateOptions{})

	if err != nil && apierrors.IsAlreadyExists(err) {
		return errors.New(errors.DuplicatedRoleName, err.Error())
	}

	return WrapClientError(err)
}

func (n namespaceReaderWriter) CreateServiceAccount(ctx context.Context, namespaceName string, roleArn string) error {
	annotation := make(map[string]string)
	switch configs.GetServiceInfo().Vendor {
	case string(constants.AWS):
		annotation[constants.AnnotationServiceAccountRole] = roleArn
	case string(constants.GCP):
		annotation[constants.AnnotationServiceAccountRoleGCP] = roleArn
	case string(constants.Azure):
		annotation[constants.AnnotationServiceAccountRoleAzure] = roleArn
	}

	_, err := n.kubeClient.CoreV1().ServiceAccounts(namespaceName).Create(ctx, &v1.ServiceAccount{
		ObjectMeta: metav1.ObjectMeta{
			Name:        namespaceName,
			Namespace:   namespaceName,
			Annotations: annotation,
		},
	}, metav1.CreateOptions{})
	if err != nil && client.IgnoreNotFound(err) != nil {
		return err
	}
	return nil
}

func (n namespaceReaderWriter) IsNamespaceExisted(ctx context.Context, namespace string) (bool, error) {
	_, err := n.kubeClient.CoreV1().
		Namespaces().
		Get(ctx, namespace, metav1.GetOptions{})

	if err == nil {
		return true, nil
	} else if client.IgnoreNotFound(err) == nil {
		return false, nil
	} else {
		return false, WrapClientError(err)
	}
}

func (n namespaceReaderWriter) Update(ctx context.Context, namespace *v1.Namespace) error {
	_, err := n.kubeClient.CoreV1().Namespaces().Update(ctx, namespace, metav1.UpdateOptions{})
	return WrapClientError(err)
}

func (n namespaceReaderWriter) Get(ctx context.Context, name string) (*v1.Namespace, error) {
	ns, err := n.kubeClient.CoreV1().Namespaces().Get(ctx, name, metav1.GetOptions{})
	if err != nil && client.IgnoreNotFound(err) == nil {
		return nil, nil
	}
	if err != nil {
		return nil, WrapClientError(err)
	}
	return ns, nil
}
