package logredactionpolicy

import (
	"context"
	"strconv"

	globalngv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/nextgen/v1"
	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/resourcepoolpolicy"
	servicecommon "github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/service/common"
	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/service/workflow/common"
	"github.com/tidbcloud/tidb-management-service/utilities/bizerr"
	"github.com/tidbcloud/tidb-management-service/utilities/workflow"
)

func (svc *service) UpdateLogRedactionPolicy(
	ctx context.Context,
	policy *globalngv1.LogRedactionPolicy,
	validateOnly bool,
) (*globalngv1.LogRedactionPolicy, bizerr.BizError) {
	ctx, span := tracer.Start(ctx, "UpdateLogRedactionPolicy")
	defer span.End()

	cluster, err := svc.clusterRepo.Get(ctx, policy.ClusterId, false)
	if err != nil {
		return nil, err
	}
	if cluster == nil {
		return nil, bizerr.New(bizerr.ErrCodeRecordNotFound, "cluster not found")
	}
	if berr := servicecommon.CheckClusterResourcePoolLifecycle(
		ctx, svc.resourcePoolRepo, cluster, resourcepoolpolicy.OperationUpdateInstance,
	); berr != nil {
		return nil, berr
	}

	if cluster.State != globalngv1.Cluster_AVAILABLE && cluster.State != globalngv1.Cluster_MODIFYING {
		return nil, bizerr.New(bizerr.ErrCodeParams, "cluster is not available or modifying")
	}

	region, err := svc.regionRepo.Get(ctx, cluster.RegionId)
	if err != nil {
		return nil, err
	}

	currentPolicy, err := svc.getLogRedactionPolicy(ctx, cluster, region)
	if err != nil {
		return nil, err
	}

	if validateOnly {
		return policy, nil
	}

	if currentPolicy.RedactLog == policy.RedactLog {
		return policy, nil
	}

	errx := svc.transaction.Transaction(ctx, func(ctx context.Context) error {
		if berr := servicecommon.LockClusterResourcePoolLifecycle(
			ctx, svc.resourcePoolRepo, cluster, resourcepoolpolicy.OperationUpdateInstance,
		); berr != nil {
			return berr
		}
		if err := svc.logRedactionPolicyRepo.Upsert(ctx, policy); err != nil {
			return bizerr.WrapError(err, "failed to upsert log redaction policy")
		}

		workFlowErr := svc.wf.RunDagWithBizId(
			ctx,
			common.UpdateLogRedactionPolicy,
			strconv.FormatUint(cluster.ClusterId, 10),
			"0",
			strconv.FormatUint(cluster.ClusterId, 10),
			map[string]string{
				workflow.KeyTraceId: workflow.GetTraceId(ctx),
				common.KeyClusterId: strconv.FormatUint(cluster.ClusterId, 10),
			},
		)
		if workFlowErr != nil {
			return bizerr.WrapErrorWithCode(workFlowErr, bizerr.ErrCodeUnknown, "create async workflow failed")
		}

		return nil
	})
	if errx != nil {
		return nil, bizerr.WrapError(errx, "update log redaction policy failed")
	}

	return policy, nil
}
