package serviceaccount

import (
	"context"
	"fmt"
	"strings"

	apierrors "k8s.io/apimachinery/pkg/api/errors"

	"github.com/grafana/authlib/types"
	iamv0alpha1 "github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1"
	"github.com/grafana/grafana/pkg/apimachinery/identity"
	"github.com/grafana/grafana/pkg/services/serviceaccounts"
)

func ValidateOnCreate(ctx context.Context, obj *iamv0alpha1.ServiceAccount) error {
	if obj.Spec.Title == "" {
		return apierrors.NewBadRequest("service account must have a title")
	}

	requester, err := identity.GetRequester(ctx)
	if err != nil {
		return apierrors.NewUnauthorized("no identity found")
	}

	requestedRole := identity.RoleType(obj.Spec.Role)
	if !requestedRole.IsValid() {
		return apierrors.NewBadRequest(fmt.Sprintf("invalid role: %s", requestedRole))
	}

	if obj.Spec.Plugin != "" {
		if !strings.HasPrefix(obj.Spec.Title, serviceaccounts.ExtSvcPrefix) {
			return apierrors.NewBadRequest("title of external service accounts must start with " + serviceaccounts.ExtSvcPrefix)
		}

		if !strings.HasSuffix(obj.Spec.Title, strings.ToLower(obj.Spec.Plugin)) {
			return apierrors.NewBadRequest("title of external service accounts must end with " + strings.ToLower(obj.Spec.Plugin))
		}

		if !requester.IsIdentityType(types.TypeAccessPolicy) {
			return apierrors.NewForbidden(iamv0alpha1.ServiceAccountResourceInfo.GroupResource(),
				obj.Name,
				fmt.Errorf("only service identities can create external service accounts"))
		}

		if obj.Spec.Role != iamv0alpha1.ServiceAccountOrgRoleNone {
			return apierrors.NewBadRequest("external service accounts must have role None")
		}
	}

	if !requester.HasRole(requestedRole) {
		return apierrors.NewForbidden(iamv0alpha1.ServiceAccountResourceInfo.GroupResource(),
			obj.Name,
			fmt.Errorf("cannot assign a role higher than user's role"))
	}

	return nil
}
