package gcp

import (
	"context"
	"fmt"
	"strings"
)

const (
	gkePolicyControlProjectRoleID          = "tidbCloudGKEPolicyControl"
	gkePolicyControlProjectRoleTitle       = "TiDB Cloud GKE Policy Control"
	gkePolicyControlProjectRoleDescription = "Least-privilege role for cluster-agent to enable GKE Policy Control."
	serviceAccountMemberPrefix             = "serviceAccount:"
	principalMemberPrefix                  = "principal://"
	principalSetMemberPrefix               = "principalSet://"
)

var gkePolicyControlProjectPermissions = []string{
	"serviceusage.services.get",
	"serviceusage.services.enable",
	"servicemanagement.services.bind",
	"serviceusage.operations.get",
	"resourcemanager.projects.get",
	"container.clusters.get",
	"container.clusters.update",
	"container.operations.get",
	"gkehub.features.get",
	"gkehub.features.create",
	"gkehub.features.update",
	"gkehub.memberships.create",
	"gkehub.operations.get",
}

func EnsureGKEPolicyControlProjectPolicy(ctx context.Context, resourceManager ResourceManagerClient, projectID, identity string) error {
	projectID = strings.TrimSpace(projectID)
	identity = strings.TrimSpace(identity)
	if resourceManager == nil {
		return fmt.Errorf("resource manager is nil")
	}
	if projectID == "" {
		return fmt.Errorf("project is empty")
	}
	if identity == "" {
		return fmt.Errorf("identity is empty")
	}

	role, err := resourceManager.EnsureProjectCustomRole(ctx, projectID, gkePolicyControlProjectRoleID, ProjectCustomRole{
		Title:               gkePolicyControlProjectRoleTitle,
		Description:         gkePolicyControlProjectRoleDescription,
		IncludedPermissions: append([]string{}, gkePolicyControlProjectPermissions...),
	})
	if err != nil {
		return err
	}

	return resourceManager.AddProjectPolicyBinding(ctx, projectID, role, GKEPolicyControlIAMMember(identity))
}

func GKEPolicyControlIAMMember(identity string) string {
	identity = strings.TrimSpace(identity)
	if identity == "" {
		return ""
	}
	if strings.HasPrefix(identity, serviceAccountMemberPrefix) ||
		strings.HasPrefix(identity, principalMemberPrefix) ||
		strings.HasPrefix(identity, principalSetMemberPrefix) {
		return identity
	}
	return serviceAccountMemberPrefix + identity
}

func CanonicalProjectIdentifier(project string) string {
	return strings.TrimSpace(strings.TrimPrefix(strings.TrimSpace(project), "projects/"))
}

func ProjectIdentifierKind(project string) string {
	project = CanonicalProjectIdentifier(project)
	for _, r := range project {
		if r < '0' || r > '9' {
			return "id"
		}
	}
	return "number"
}
