package logredactionpolicy

import (
	"context"
	"strconv"

	clusterngv1beta "github.com/tidbcloud/cluster-service-ng/api/cluster-service-ng/v1beta"
	pkgclusterproxy "github.com/tidbcloud/pkgv2/clusterproxy"
	"github.com/tidbcloud/pkgv2/db"
	"go.opentelemetry.io/otel"

	globalngv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/nextgen/v1"
	"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"
	clusterrepo "github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/repository/cluster"
	logredactionpolicyrepo "github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/repository/logredactionpolicy"
	regionrepo "github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/repository/region"
	resourcepoolrepo "github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/repository/resourcepool"
	tidbgrouprepo "github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/repository/tidbgroup"
	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/pkg/config"
	"github.com/tidbcloud/tidb-management-service/utilities/bizerr"
	"github.com/tidbcloud/tidb-management-service/utilities/workflow"
)

var tracer = otel.Tracer("domain.logredactionpolicy")

type Service interface {
	GetLogRedactionPolicy(ctx context.Context, clusterID uint64) (*globalngv1.LogRedactionPolicy, bizerr.BizError)
	UpdateLogRedactionPolicy(
		ctx context.Context,
		policy *globalngv1.LogRedactionPolicy,
		validateOnly bool,
	) (*globalngv1.LogRedactionPolicy, bizerr.BizError)
	GetPlatformAdminClusterProxy(
		ctx context.Context,
		cluster *entity.Cluster,
		regionEn *entity.Region,
		tidbgroup *entity.TidbGroup,
	) (clusterproxy.ClusterProxy, bizerr.BizError)
	UpdateLogRedactionPolicyViaAgent(
		ctx context.Context,
		cluster *entity.Cluster,
		region *entity.Region,
		tidbgroup *entity.TidbGroup,
		redactLog bool,
	) bizerr.BizError
	GetLogRedactionPolicyViaAgent(
		ctx context.Context,
		cluster *entity.Cluster,
		region *entity.Region,
		tidbgroup *entity.TidbGroup,
	) (*globalngv1.LogRedactionPolicy, bizerr.BizError)
}

type service struct {
	clusterRepo            clusterrepo.Repo
	tidbGroupRepo          tidbgrouprepo.Repo
	regionRepo             regionrepo.Repo
	logRedactionPolicyRepo logredactionpolicyrepo.Repo
	regionalServerCli      regionalserver.Client
	clusterProxyProvider   clusterproxy.Provider
	encryptor              remoteencryptor.Client
	wf                     workflow.Workflow
	transaction            db.Transactioner
	cfg                    *config.Config
	resourcePoolRepo       resourcepoolrepo.Repo
}

func NewService(
	clusterRepo clusterrepo.Repo,
	tidbGroupRepo tidbgrouprepo.Repo,
	regionRepo regionrepo.Repo,
	logRedactionPolicyRepo logredactionpolicyrepo.Repo,
	regionalServerCli regionalserver.Client,
	clusterProxyProvider clusterproxy.Provider,
	encryptor remoteencryptor.Client,
	wf workflow.Workflow,
	transaction db.Transactioner,
	cfg *config.Config,
	resourcePoolRepo resourcepoolrepo.Repo,
) Service {
	return &service{
		clusterRepo:            clusterRepo,
		tidbGroupRepo:          tidbGroupRepo,
		regionRepo:             regionRepo,
		logRedactionPolicyRepo: logRedactionPolicyRepo,
		regionalServerCli:      regionalServerCli,
		clusterProxyProvider:   clusterProxyProvider,
		encryptor:              encryptor,
		wf:                     wf,
		transaction:            transaction,
		cfg:                    cfg,
		resourcePoolRepo:       resourcePoolRepo,
	}
}

func (svc *service) GetPlatformAdminClusterProxy(
	ctx context.Context,
	cluster *entity.Cluster,
	regionEn *entity.Region,
	tidbgroup *entity.TidbGroup,
) (clusterproxy.ClusterProxy, bizerr.BizError) {
	// Get audit log status from cluster via cluster proxy.
	platformAdminPwd, err := svc.encryptor.DecryptBase64(ctx, cluster.EncryptedPlatformAdminPassword)
	if err != nil {
		return nil, err
	}

	regionalTidbGroup, err := svc.regionalServerCli.GetTidbGroup(
		ctx,
		regionEn,
		&clusterngv1beta.GetTiDBGroupRequest{
			ClusterId:   strconv.FormatUint(cluster.ClusterId, 10),
			TidbGroupId: strconv.FormatUint(tidbgroup.Id, 10),
		},
	)
	if err != nil {
		return nil, err
	}

	proxyBaseUrl := clusterproxy.BuildProxyBaseUrl(
		regionEn.ServiceAddress,
		regionalTidbGroup.GetSharedPoolId(),
		cluster.ClusterId,
		tidbgroup.Id,
	)
	proxy, err := svc.clusterProxyProvider.GetClusterProxy(
		ctx,
		cluster.ClusterId,
		proxyBaseUrl,
		cluster.Version,
		&pkgclusterproxy.ClusterOperator{
			Username:   clusterproxy.PlatformAdminUser,
			AuthMethod: pkgclusterproxy.AuthMethodPassword,
			Credential: platformAdminPwd,
		},
	)
	if err != nil {
		return nil, err
	}

	return proxy, nil
}
