package resourcemanager

import (
	"context"

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

	v1 "github.com/tidbcloud/observability/api/regionalserver/resourceworker/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"sigs.k8s.io/controller-runtime/pkg/client"
)

type iamReaderWriter struct {
	cli client.Client
}

func (p iamReaderWriter) CreateRole(ctx context.Context, data *v1.IAM) error {
	err := p.cli.Create(ctx, data)
	if err != nil && apierrors.IsAlreadyExists(err) {
		return errors.New(errors.DuplicatedRoleName, err.Error())
	}
	return WrapClientError(err)
}

func (p iamReaderWriter) DeleteRole(ctx context.Context, roleName string, ns string) error {
	role := &v1.IAM{
		ObjectMeta: metav1.ObjectMeta{
			Name:      roleName,
			Namespace: ns,
		},
	}
	err := p.cli.Delete(ctx, role)
	if apierrors.IsNotFound(err) {
		return nil
	}
	return WrapClientError(err)
}

func (p iamReaderWriter) GetRoles(ctx context.Context, ns string, labelSelector map[string]string) (*v1.IAMList, error) {
	roleList := &v1.IAMList{}
	err := p.cli.List(ctx, roleList, client.InNamespace(ns), client.MatchingLabels(labelSelector))
	if err != nil {
		return nil, WrapClientError(err)
	}
	return roleList, nil
}

func (p iamReaderWriter) DeleteRoles(ctx context.Context, ns string, labelSelector map[string]string) error {
	roleList := &v1.IAMList{}
	err := p.cli.List(ctx, roleList, client.InNamespace(ns), client.MatchingLabels(labelSelector))
	if err != nil {
		return WrapClientError(err)
	}

	for _, role := range roleList.Items {
		r := role
		err = p.cli.Delete(ctx, &r)
		if client.IgnoreNotFound(err) != nil {
			return WrapClientError(err)
		}
	}
	return nil
}

func (p iamReaderWriter) UpdateRole(ctx context.Context, data *v1.IAM) error {
	err := p.cli.Update(ctx, data)
	return WrapClientError(err)
}

func (p iamReaderWriter) IsRoleExists(ctx context.Context, roleName string, ns string) (bool, error) {
	err := p.cli.Get(ctx, client.ObjectKey{
		Name:      roleName,
		Namespace: ns,
	}, new(v1.IAM))

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

func (p iamReaderWriter) GetRole(ctx context.Context, roleName string, ns string) (role *v1.IAM, err error) {
	role = new(v1.IAM)
	err = p.cli.Get(ctx, client.ObjectKey{
		Name:      roleName,
		Namespace: ns,
	}, role)

	if err != nil && client.IgnoreNotFound(err) == nil {
		err = errors.NewErrorf(errors.RoleNotFound, "role %s is not found", roleName)
		return role, err
	}
	return role, WrapClientError(err)
}
