package cluster

import (
	"context"
	"strconv"

	"github.com/tidbcloud/tiinf/sdk/auditlog"

	globaldedicatedv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/dedicated/v1"
	openapidedicatedv1beta1 "github.com/tidbcloud/tidb-management-service/api/spec/tidb_cloud_open_api/dedicated/v1beta1"
	"github.com/tidbcloud/tidb-management-service/tidb-mgmt-service/domain/adapter/eventbus"
	"github.com/tidbcloud/tidb-management-service/utilities/bizerr"
	"github.com/tidbcloud/tidb-management-service/utilities/grpc/metadata"
)

func (c *serverImpl) GetLogRedactionPolicy(
	ctx context.Context,
	req *openapidedicatedv1beta1.GetLogRedactionPolicyRequest,
) (*openapidedicatedv1beta1.LogRedactionPolicy, error) {
	ctx, span := tracer.Start(ctx, "GetLogRedactionPolicy")
	defer span.End()

	// Extract request meta.
	_, err := metadata.ExtractRequestMetaWithCheckPermission(ctx)
	if err != nil {
		return nil, bizerr.WrapErrorWithCode(err, bizerr.ErrCodeParams, "failed to extract request metadata")
	}

	var clusterId uint64
	clusterId, err = strconv.ParseUint(req.GetClusterId(), 10, 64)
	if err != nil {
		return nil, bizerr.WrapErrorWithCode(err, bizerr.ErrCodeParams, "invalid cluster id")
	}
	logRedaction, err := c.clusterSvc.GetLogRedactionPolicy(ctx, clusterId)
	if err != nil {
		return nil, err
	}
	return cvtOpenAPILogRedactionPolicy(logRedaction), nil
}

func (c *serverImpl) UpdateLogRedactionPolicy(
	ctx context.Context,
	req *openapidedicatedv1beta1.UpdateLogRedactionPolicyRequest,
) (*openapidedicatedv1beta1.LogRedactionPolicy, error) {
	ctx, span := tracer.Start(ctx, "UpdateLogRedactionPolicy")
	defer span.End()

	var (
		err                       error
		reqMeta                   *metadata.RequestMeta
		requestLogRedactionPolicy *globaldedicatedv1.LogRedactionPolicy
		updatedLogRedactionPolicy *globaldedicatedv1.LogRedactionPolicy
	)

	detailsFunc := func() auditlog.Details {
		details := eventbus.NewAuditLogDetails(eventbus.TierTypeDedicated)
		details[auditlog.KeyNewLogRedactionPolicy] = req.GetLogRedactionPolicy().GetRedactLog()
		return details
	}

	defer func() {
		c.auditLogSender.SubmitAuditLog(ctx, auditlog.EventUpdateLogRedactionPolicy, reqMeta, detailsFunc, err)
	}()

	// Extract request meta.
	reqMeta, err = metadata.ExtractRequestMetaWithCheckPermission(ctx)
	if err != nil {
		return nil, bizerr.WrapErrorWithCode(err, bizerr.ErrCodeParams, "failed to extract request metadata")
	}

	requestLogRedactionPolicy, err = cvtDedicatedLogRedactionPolicy(req.GetLogRedactionPolicy())
	if err != nil {
		return nil, err
	}

	updatedLogRedactionPolicy, err = c.clusterSvc.UpdateLogRedactionPolicy(ctx, requestLogRedactionPolicy)
	if err != nil {
		return nil, err
	}
	return cvtOpenAPILogRedactionPolicy(updatedLogRedactionPolicy), nil
}

func cvtOpenAPILogRedactionPolicy(
	logRedactionPolicy *globaldedicatedv1.LogRedactionPolicy,
) *openapidedicatedv1beta1.LogRedactionPolicy {
	return &openapidedicatedv1beta1.LogRedactionPolicy{
		ClusterId: strconv.FormatUint(logRedactionPolicy.GetClusterId(), 10),
		RedactLog: logRedactionPolicy.RedactLog,
	}
}

func cvtDedicatedLogRedactionPolicy(
	logRedactionPolicy *openapidedicatedv1beta1.LogRedactionPolicy,
) (*globaldedicatedv1.LogRedactionPolicy, bizerr.BizError) {
	clusterId, err := strconv.ParseUint(logRedactionPolicy.GetClusterId(), 10, 64)
	if err != nil {
		return nil, bizerr.WrapErrorWithCode(err, bizerr.ErrCodeParams, "invalid cluster id")
	}
	return &globaldedicatedv1.LogRedactionPolicy{
		ClusterId: clusterId,
		RedactLog: logRedactionPolicy.RedactLog,
	}, nil
}
