package common

import (
	"context"
	"strconv"

	clusterngv1beta "github.com/tidbcloud/cluster-service-ng/api/cluster-service-ng/v1beta"

	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/adapter/clusterproxy"
	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/adapter/regionalserver"
	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/adapter/remoteencryptor"
	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/entity"
	"github.com/tidbcloud/tidb-management-service/utilities/bizerr"
)

// ClusterAgentCredentials carries the encrypted platform_admin credentials
// and shared pool id needed to call cluster-agent RPCs.
type ClusterAgentCredentials struct {
	SharedPoolID      string
	EncryptedUsername []byte
	EncryptedPassword []byte
}

// BuildClusterAgentCredentials resolves the cluster's shared pool id, fetches the
// cluster-agent RSA public key, decrypts the stored platform_admin password,
// then re-encrypts user+pwd for transport to cluster-agent. Extracted so audit log,
// log redaction policy, and future cluster-agent callers share one code path.
func BuildClusterAgentCredentials(
	ctx context.Context,
	regionalCli regionalserver.Client,
	encryptor remoteencryptor.Client,
	cluster *entity.Cluster,
	region *entity.Region,
	tidbgroup *entity.TidbGroup,
) (*ClusterAgentCredentials, bizerr.BizError) {
	regionalTidbGroup, err := regionalCli.GetTidbGroup(
		ctx,
		region,
		&clusterngv1beta.GetTiDBGroupRequest{
			ClusterId:   strconv.FormatUint(cluster.ClusterId, 10),
			TidbGroupId: strconv.FormatUint(tidbgroup.Id, 10),
		},
	)
	if err != nil {
		return nil, err
	}

	sharedPoolID := regionalTidbGroup.GetSharedPoolId()

	publicKeyPem, err := regionalCli.GetClusterAgentPublicKey(
		ctx,
		region,
		strconv.FormatUint(cluster.ClusterId, 10),
		sharedPoolID,
	)
	if err != nil {
		return nil, err
	}

	publicKey, parseErr := ParsePublicKeyFromPEM(publicKeyPem)
	if parseErr != nil {
		return nil, bizerr.New(bizerr.ErrCodeRegionalAPI, "parse public key: %s", parseErr.Error())
	}

	platformAdminPwd, err := encryptor.DecryptBase64(ctx, cluster.EncryptedPlatformAdminPassword)
	if err != nil {
		return nil, err
	}

	encryptedUsername, encUserErr := EncryptWithPublicKey(publicKey, []byte(clusterproxy.PlatformAdminUser))
	if encUserErr != nil {
		return nil, bizerr.New(bizerr.ErrCodeRegionalAPI, "encrypt username: %s", encUserErr.Error())
	}
	encryptedPassword, encPwdErr := EncryptWithPublicKey(publicKey, []byte(platformAdminPwd))
	if encPwdErr != nil {
		return nil, bizerr.New(bizerr.ErrCodeRegionalAPI, "encrypt password: %s", encPwdErr.Error())
	}

	return &ClusterAgentCredentials{
		SharedPoolID:      sharedPoolID,
		EncryptedUsername: encryptedUsername,
		EncryptedPassword: encryptedPassword,
	}, nil
}
