package gardener

// copy from https://github.com/tidbcloud/dbaas/blob/5c4fd52a6d7d3afe6d248bfe4880e3c82b80c4c5/central/runtime/util/util.go#L1
// with some change to drop depend on other pkg in dbaas repo.

import (
	"crypto/md5"
	"fmt"

	"github.com/pingcap/errors"

	"github.com/tidbcloud/infra-api/pkg/consts"
)

const (
	/* #nosec */
	gcpKMSSecretName string = "gcp-kms-credentials"

	externalIdSalt = "infra-api"

	GcpKMSSecretName = gcpKMSSecretName
)

// get Bucket via projectID region and network projectId
func getBucketName(projectID string, region string, infraProject string) string {
	return fmt.Sprintf("dbaas-%s-%s-%s", projectID, region, infraProject)
}

func getImportRoleName(projectID string, shootName string, infraProject string) string {
	return fmt.Sprintf("dbaas-%s-%s-%s-import", projectID, infraProject, shootName)
}

func getGCPReporterAWSRoleName(project string, infraProject string, shootName string) string {
	return fmt.Sprintf("dbaas-gcp-%s-%s-%s-reporter", project, infraProject, shootName)
}

func getGCPTiKVAWSUserName(project string, infraProject string, shootName string) string {
	return fmt.Sprintf("dbaas-gcp-%s-%s-%s-tikv", project, infraProject, shootName)
}

func getGCPAccessServiceAccountName(region, projectID string) string {
	suffix := md5.Sum([]byte(fmt.Sprintf("%s-%s", region, projectID)))
	// GCP has a limit on the length of the SA name: [6, 30], so we trim the MD5 hash.
	suffixStr := fmt.Sprintf("%x", suffix)[:16]
	return fmt.Sprintf("access-sa-%s", suffixStr)
}

func getGCPAccessServiceAccountKeyName(saName string) string {
	return fmt.Sprintf("%s-key", saName)
}

func getGCPAccessServiceAccountEmail(saName, gcpProjectName string) string {
	return fmt.Sprintf("%s@%s.iam.gserviceaccount.com", saName, gcpProjectName)
}

func getExternalId(roleARN string) string {
	h := md5.New()
	h.Write([]byte(roleARN))
	bs := h.Sum([]byte(externalIdSalt))

	return fmt.Sprintf("%x", bs)
}

func getGCPPCARoleName(project string, infraProject string, shootName string) string {
	return fmt.Sprintf("dbaas-gcp-%s-%s-%s-pcm", project, infraProject, shootName)
}

// ref https://github.com/tidbcloud/dbaas/blob/717863b951d85b99660c7fbcacb2aa5b19b40f22/central/runtime/deployer/gardener/shoot_cluster.go#L561
// gardenProject is the gardener project name.
func getShootWorkerIamIdentity(providerType string, projectName string, shootName string, accountOrProjectID string) (string, error) {
	switch providerType {
	case consts.ProviderTypeAWS:
		return fmt.Sprintf("arn:aws:iam::%s:role/shoot--%s--%s-nodes", accountOrProjectID, projectName, shootName), nil
	case consts.ProviderTypeGCP:
		return fmt.Sprintf("shoot--%s--%s@%s.iam.gserviceaccount.com", projectName, shootName, accountOrProjectID), nil
	default:
		return "", errors.Errorf("unknown provider type %q", providerType)
	}
}

func GetBucketName(projectID string, region string, infraProject string) string {
	return getBucketName(projectID, region, infraProject)
}

func GetImportIamIdentity(providerType string, projectId string, shootName string, infraProject string, accountOrProjectID string) (string, error) {
	name := getImportRoleName(projectId, shootName, infraProject)
	var identity string

	switch providerType {
	case consts.ProviderTypeAWS:
		identity = fmt.Sprintf("arn:aws:iam::%s:role/%s", accountOrProjectID, name)
	case consts.ProviderTypeGCP:
		fallthrough
	default:
		return "", fmt.Errorf("unknown provider type %s", providerType)
	}

	return identity, nil
}

func GetImportRoleName(projectID string, shootName string, infraProject string) string {
	return getImportRoleName(projectID, shootName, infraProject)
}

func GetGCPReporterAWSRoleName(project string, infraProject string, shootName string) string {
	return getGCPReporterAWSRoleName(project, infraProject, shootName)
}

func GetGCPTiKVAWSUserName(project string, infraProject string, shootName string) string {
	return getGCPTiKVAWSUserName(project, infraProject, shootName)
}

func GetGCPPCARoleName(project string, infraProject string, shootName string) string {
	return getGCPPCARoleName(project, infraProject, shootName)
}

func GetShootWorkerIamIdentity(providerType string, projectName string, shootName string, accountOrProjectID string) (string, error) {
	return getShootWorkerIamIdentity(providerType, projectName, shootName, accountOrProjectID)
}

func GetGCPAccessServiceAccountName(region, projectID string) string {
	return getGCPAccessServiceAccountName(region, projectID)
}

func GetGCPAccessServiceAccountEmail(saName, gcpProjectName string) string {
	return getGCPAccessServiceAccountEmail(saName, gcpProjectName)
}

func GetGCPAccessServiceAccountKeyName(saName string) string {
	return getGCPAccessServiceAccountKeyName(saName)
}
