package sqluser

import (
	"context"
	"fmt"
	"strconv"
	"strings"

	"braces.dev/errtrace"
	"github.com/tidbcloud/pkgv2/clusterproxy"

	globalserverlessv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/serverless/v1"
	"github.com/tidbcloud/tidb-management-service/serverless-global-service/domain/constant"
	"github.com/tidbcloud/tidb-management-service/utilities/bizerr"
)

func (s *sqlUserSvcImpl) UpdateSqlUserPassword(
	ctx context.Context,
	req *globalserverlessv1.ChangeSqlUserPasswdRequest,
) error {
	ctx, span := Tracer.Start(ctx, "Domain.ChangePassword")
	defer span.End()

	en, regionalCluster, err := s.getCluster(ctx, req.ClusterId)
	if err != nil {
		return errtrace.Wrap(err)
	}

	if isPGStarterClusterForPassword(en) {
		if en.ExternalInstanceID == "" {
			return bizerr.New(bizerr.ErrCodeParams, "missing external instance id for pg cluster")
		}
		if _, err := s.sys9Lifecycle.RotateManagedDatabaseAdministrativeCredential(ctx, en, en.ExternalInstanceID, ""); err != nil {
			return errtrace.Wrap(err)
		}
		en.HasSetPwd = true
		if err := s.clusterRepo.Save(ctx, en); err != nil {
			return errtrace.Wrap(err)
		}
		return nil
	}

	adminPasswd, err := s.encryptor.DecryptBase64(ctx, en.EncryptedCloudAdminPassword)
	if err != nil {
		return fmt.Errorf("decrypt cluster admin password failed: %w", err)
	}

	// use cloud_admin to manage password
	operator := &clusterproxy.ClusterOperator{
		Username:   constant.DBUserCloudAdmin,
		AuthMethod: clusterproxy.AuthMethodPassword,
		Credential: adminPasswd,
	}
	cid, err := strconv.ParseUint(regionalCluster.ClusterId, 10, 64)
	if err != nil {
		return bizerr.WrapError(err, "invalid cluster id: %s", regionalCluster.ClusterId)
	}
	proxy, err := s.clusterProxyProvider.GetClusterProxy(
		ctx,
		cid,
		regionalCluster.ProxyEndpoint,
		regionalCluster.Version,
		operator,
	)
	if err != nil {
		return errtrace.Wrap(err)
	}

	if err := proxy.ChangePassword(ctx, req.UserName, req.Passwd); err != nil {
		return errtrace.Wrap(bizerr.WrapErrorWithCode(err, bizerr.ErrCodeSvcInfraAPI, "change cluster password"))
	}

	if strings.HasSuffix(req.UserName, constant.DBUserRoot) {
		en.HasSetPwd = true
		if err := s.clusterRepo.Save(ctx, en); err != nil {
			return errtrace.Wrap(err)
		}
		return nil
	}

	return nil
}
